Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

MDL-35238 Fetch the package and store it in a temporary location

  • Loading branch information...
commit 4c72f55516403fcdaa1329952b349b109c56c9ef 1 parent af29dad
David Mudrák mudrd8mz authored

Showing 3 changed files with 154 additions and 5 deletions. Show diff stats Hide diff stats

  1. +1 1  lib/pluginlib.php
  2. +145 4 mdeploy.php
  3. +8 0 mdeploytest.php
2  lib/pluginlib.php
@@ -1596,7 +1596,7 @@ public function make_execution_widget(available_update_info $info) {
1596 1596 'type' => $plugintype,
1597 1597 'name' => $pluginname,
1598 1598 'typeroot' => $pluginrootpaths[$plugintype],
1599   - 'download' => $info->download,
  1599 + 'package' => $info->download,
1600 1600 'dataroot' => $CFG->dataroot,
1601 1601 'dirroot' => $CFG->dirroot,
1602 1602 'passfile' => $passfile,
149 mdeploy.php
@@ -20,6 +20,11 @@
20 20 *
21 21 * This script looks after deploying available updates to the local Moodle site.
22 22 *
  23 + * CLI usage example:
  24 + * $ sudo -u apache php mdeploy.php --upgrade \
  25 + * --package=https://moodle.org/plugins/download.php/...zip \
  26 + * --dataroot=/home/mudrd8mz/moodledata/moodle24
  27 + *
23 28 * @package core
24 29 * @copyright 2012 David Mudrak <david@moodle.com>
25 30 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -34,7 +39,9 @@
34 39
35 40 class invalid_coding_exception extends Exception {}
36 41 class missing_option_exception extends Exception {}
  42 +class invalid_option_exception extends Exception {}
37 43 class unauthorized_access_exception extends Exception {}
  44 +class download_file_exception extends Exception {}
38 45
39 46
40 47 // Various support classes /////////////////////////////////////////////////////
@@ -106,6 +113,7 @@ class input_manager extends singleton_pattern {
106 113 const TYPE_INT = 'int'; // Integer
107 114 const TYPE_PATH = 'path'; // Full path to a file or a directory
108 115 const TYPE_RAW = 'raw'; // Raw value, keep as is
  116 + const TYPE_URL = 'url'; // URL to a file
109 117
110 118 /** @var input_cli_provider|input_http_provider the provider of the input */
111 119 protected $inputprovider = null;
@@ -155,12 +163,13 @@ public function get_option($name, $default = 'provide_default_value_explicitly')
155 163 public function get_option_info($name=null) {
156 164
157 165 $supportedoptions = array(
  166 + array('', 'passfile', input_manager::TYPE_FILE, 'File name of the passphrase file (HTTP access only)'),
  167 + array('', 'password', input_manager::TYPE_RAW, 'Session passphrase (HTTP access only)'),
158 168 array('d', 'dataroot', input_manager::TYPE_PATH, 'Full path to the dataroot (moodledata) directory'),
159 169 array('h', 'help', input_manager::TYPE_FLAG, 'Prints usage information'),
160 170 array('i', 'install', input_manager::TYPE_FLAG, 'Installation mode'),
  171 + array('p', 'package', input_manager::TYPE_URL, 'URL to the ZIP package to deploy'),
161 172 array('u', 'upgrade', input_manager::TYPE_FLAG, 'Upgrade mode'),
162   - array('', 'passfile', input_manager::TYPE_FILE, 'File name of the passphrase file (HTTP access only)'),
163   - array('', 'password', input_manager::TYPE_RAW, 'Session passphrase (HTTP access only)'),
164 173 );
165 174
166 175 if (is_null($name)) {
@@ -249,6 +258,20 @@ public function cast_value($raw, $type) {
249 258 case input_manager::TYPE_RAW:
250 259 return $raw;
251 260
  261 + case input_manager::TYPE_URL:
  262 + $regex = '^(https?|ftp)\:\/\/'; // protocol
  263 + $regex .= '([a-z0-9+!*(),;?&=\$_.-]+(\:[a-z0-9+!*(),;?&=\$_.-]+)?@)?'; // optional user and password
  264 + $regex .= '[a-z0-9+\$_-]+(\.[a-z0-9+\$_-]+)*'; // hostname or IP (one word like http://localhost/ allowed)
  265 + $regex .= '(\:[0-9]{2,5})?'; // port (optional)
  266 + $regex .= '(\/([a-z0-9+\$_-]\.?)+)*\/?'; // path to the file
  267 + $regex .= '(\?[a-z+&\$_.-][a-z0-9;:@/&%=+\$_.-]*)?'; // HTTP params
  268 +
  269 + if (preg_match('#'.$regex.'#i', $raw)) {
  270 + return $raw;
  271 + } else {
  272 + return '';
  273 + }
  274 +
252 275 default:
253 276 throw new invalid_coding_exception('Unknown option type.');
254 277
@@ -582,6 +605,15 @@ class worker extends singleton_pattern {
582 605 /** @var output_manager */
583 606 protected $output = null;
584 607
  608 + /** @var int the most recent cURL error number, zero for no error */
  609 + private $curlerrno = null;
  610 +
  611 + /** @var string the most recent cURL error message, empty string for no error */
  612 + private $curlerror = null;
  613 +
  614 + /** @var array|false the most recent cURL request info, if it was successful */
  615 + private $curlinfo = null;
  616 +
585 617 /**
586 618 * Main - the one that actually does something
587 619 */
@@ -598,10 +630,22 @@ public function execute() {
598 630
599 631 if ($this->input->get_option('upgrade')) {
600 632 // Fetch the ZIP file into a temporary location.
  633 + $source = $this->input->get_option('package');
  634 + if (empty($source)) {
  635 + throw new invalid_option_exception('Not a valid package URL');
  636 + }
  637 + $target = $this->target_location($source);
601 638
602   - // Compare MD5 checksum of the ZIP file.
  639 + if ($this->download_file($source, $target)) {
  640 + $this->log('ZIP fetched into '.$target);
  641 + } else {
  642 + $this->log('cURL error ' . $this->curlerrno . ' ' . $this->curlerror);
  643 + $this->log('Unable to download the file');
  644 + }
  645 +
  646 + // Compare MD5 checksum of the ZIP file - TODO
603 647
604   - // If the target location exists, backup it.
  648 + // If the target location exists, backup it - TODO
605 649
606 650 // Unzip the ZIP file into the target location.
607 651
@@ -694,6 +738,103 @@ protected function authorize() {
694 738 throw new unauthorized_access_exception('Session passphrase does not match the stored one.');
695 739 }
696 740 }
  741 +
  742 + /**
  743 + * Choose the target location for the given ZIP's URL.
  744 + *
  745 + * @param string $source URL
  746 + * @return string
  747 + */
  748 + protected function target_location($source) {
  749 +
  750 + $dataroot = $this->input->get_option('dataroot');
  751 + $pool = $dataroot.'/mdeploy/var';
  752 +
  753 + if (!is_dir($pool)) {
  754 + mkdir($pool, 02777, true);
  755 + }
  756 +
  757 + $target = $pool.'/'.md5($source);
  758 +
  759 + $suffix = 0;
  760 + while (file_exists($target.'.'.$suffix.'.zip')) {
  761 + $suffix++;
  762 + }
  763 +
  764 + return $target.'.'.$suffix.'.zip';
  765 + }
  766 +
  767 + /**
  768 + * Downloads the given file into the given destination.
  769 + *
  770 + * This is basically a simplified version of {@link download_file_content()} from
  771 + * Moodle itself, tuned for fetching files from moodle.org servers.
  772 + *
  773 + * @param string $source file url starting with http(s)://
  774 + * @param string $target store the downloaded content to this file (full path)
  775 + * @return bool true on success, false otherwise
  776 + * @throws download_file_exception
  777 + */
  778 + protected function download_file($source, $target) {
  779 +
  780 + $newlines = array("\r", "\n");
  781 + $source = str_replace($newlines, '', $source);
  782 + if (!preg_match('|^https?://|i', $source)) {
  783 + throw new download_file_exception('Unsupported transport protocol.');
  784 + }
  785 + if (!$ch = curl_init($source)) {
  786 + // $this->log('Unable to init cURL.');
  787 + return false;
  788 + }
  789 +
  790 + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true); // verify the peer's certificate
  791 + curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 2); // check the existence of a common name and also verify that it matches the hostname provided
  792 + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // return the transfer as a string
  793 + curl_setopt($ch, CURLOPT_HEADER, false); // don't include the header in the output
  794 + curl_setopt($ch, CURLOPT_TIMEOUT, 3600);
  795 + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 20); // nah, moodle.org is never unavailable! :-p
  796 + curl_setopt($ch, CURLOPT_URL, $source);
  797 +
  798 + $targetfile = fopen($target, 'w');
  799 +
  800 + if (!$targetfile) {
  801 + throw new download_file_exception('Unable to create local file '.$target);
  802 + }
  803 +
  804 + curl_setopt($ch, CURLOPT_FILE, $targetfile);
  805 +
  806 + $result = curl_exec($ch);
  807 +
  808 + // try to detect encoding problems
  809 + if ((curl_errno($ch) == 23 or curl_errno($ch) == 61) and defined('CURLOPT_ENCODING')) {
  810 + curl_setopt($ch, CURLOPT_ENCODING, 'none');
  811 + $result = curl_exec($ch);
  812 + }
  813 +
  814 + fclose($targetfile);
  815 +
  816 + $this->curlerrno = curl_errno($ch);
  817 + $this->curlerror = curl_error($ch);
  818 + $this->curlinfo = curl_getinfo($ch);
  819 +
  820 + if (!$result or $this->curlerrno) {
  821 + return false;
  822 +
  823 + } else if (is_array($this->curlinfo) and (empty($this->curlinfo['http_code']) or $this->curlinfo['http_code'] != 200)) {
  824 + return false;
  825 + }
  826 +
  827 + return true;
  828 + }
  829 +
  830 + /**
  831 + * Log a message
  832 + *
  833 + * @param string $message
  834 + */
  835 + protected function log($message) {
  836 + // TODO
  837 + }
697 838 }
698 839
699 840
8 mdeploytest.php
@@ -127,6 +127,14 @@ public function data_for_cast_value() {
127 127 array("!@#$%|/etc/qwerty\n\n\t\n\r", input_manager::TYPE_RAW, "!@#$%|/etc/qwerty\n\n\t\n\r"),
128 128
129 129 array("\nrock'n'roll.mp3\t.exe", input_manager::TYPE_FILE, 'rocknroll.mp3.exe'),
  130 +
  131 + array('http://localhost/moodle/dev/plugin.zip', input_manager::TYPE_URL, 'http://localhost/moodle/dev/plugin.zip'),
  132 + array(
  133 + 'https://moodle.org/plugins/download.php/1292/mod_stampcoll_moodle23_2012062201.zip',
  134 + input_manager::TYPE_URL,
  135 + 'https://moodle.org/plugins/download.php/1292/mod_stampcoll_moodle23_2012062201.zip'
  136 + ),
  137 + array('file:///etc/passwd', input_manager::TYPE_URL, ''),
130 138 );
131 139 }
132 140

0 comments on commit 4c72f55

Please sign in to comment.
Something went wrong with that request. Please try again.