function module_download($modulename, $force = false, $progress_callback = null, $override_svn = false, $override_xml = false) { global $amp_conf; if ($time_limit = ini_get('max_execution_time')) { set_time_limit($time_limit); } // size of download blocks to fread() // basically, this controls how often progress_callback is called $download_chunk_size = 12 * 1024; // invoke progress callback if (function_exists($progress_callback)) { $progress_callback('getinfo', array('module' => $modulename)); } $res = module_getonlinexml($modulename, $override_xml); if ($res == null) { return array(_("Module not found in repository")); } $file = basename($res['location']); $filename = $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/" . $file; // if we're not forcing the download, and a file with the target name exists.. if (!$force && file_exists($filename)) { // We might already have it! Let's check the MD5. $filedata = ""; if ($fh = @fopen($filename, "r")) { while (!feof($fh)) { $filedata .= fread($fh, 8192); } fclose($fh); } if (isset($res['md5sum']) && $res['md5sum'] == md5($filedata)) { // Note, if there's no MD5 information, it will redownload // every time. Otherwise theres no way to avoid a corrupt // download // invoke progress callback if (function_exists($progress_callback)) { $progress_callback('untar', array('module' => $modulename, 'size' => filesize($filename))); } /* We will explode the tarball in the cache directory and then once successful, remove the old module before before * moving the new one over. This way, things like removed files end up being removed instead of laying around * * TODO: save old module being replaced, if there is an old one. */ exec("rm -rf " . $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/{$modulename}", $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not remove %s to install new version'), $amp_conf['AMPWEBROOT'] . '/admin/modules/_cache/' . $modulenam)); } exec("tar zxf " . escapeshellarg($filename) . " -C " . escapeshellarg($amp_conf['AMPWEBROOT'] . '/admin/modules/_cache/'), $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not untar %s to %s'), $filename, $amp_conf['AMPWEBROOT'] . '/admin/modules/_cache')); } exec("rm -rf " . $amp_conf['AMPWEBROOT'] . "/admin/modules/{$modulename}", $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not remove old module %s to install new version'), $amp_conf['AMPWEBROOT'] . '/admin/modules/' . $modulename)); } exec("mv " . $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/{$modulename} " . $amp_conf['AMPWEBROOT'] . "/admin/modules/{$modulename}", $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not move %s to %s'), $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/{$modulename}", $amp_conf['AMPWEBROOT'] . '/admin/modules/')); } // invoke progress_callback if (function_exists($progress_callback)) { $progress_callback('done', array('module' => $modulename)); } return true; } else { unlink($filename); } } if ($override_svn) { $url = $override_svn . $res['location']; } else { $url = "http://mirror.freepbx.org/modules/" . $res['location']; } if (!($fp = @fopen($filename, "w"))) { return array(sprintf(_("Error opening %s for writing"), $filename)); } $headers = get_headers_assoc($url); $totalread = 0; // invoke progress_callback if (function_exists($progress_callback)) { $progress_callback('downloading', array('module' => $modulename, 'read' => $totalread, 'total' => $headers['content-length'])); } // Check MODULEADMINWGET first so we don't execute the fopen() if set // if ($amp_conf['MODULEADMINWGET'] || !($dp = @fopen($url, 'r'))) { exec("wget -O {$filename} {$url} 2> /dev/null", $filedata, $retcode); if ($retcode != 0) { return array(sprintf(_("Error opening %s for reading"), $url)); } else { if (!($dp = @fopen($filename, 'r'))) { return array(sprintf(_("Error opening %s for reading"), $url)); } } } $filedata = ''; while (!feof($dp)) { $data = fread($dp, $download_chunk_size); $filedata .= $data; $totalread += strlen($data); if (function_exists($progress_callback)) { $progress_callback('downloading', array('module' => $modulename, 'read' => $totalread, 'total' => $headers['content-length'])); } } fwrite($fp, $filedata); fclose($dp); fclose($fp); if (is_readable($filename) !== TRUE) { return array(sprintf(_('Unable to save %s'), $filename)); } // Check the MD5 info against what's in the module's XML if (!isset($res['md5sum']) || empty($res['md5sum'])) { //echo "<div class=\"error\">"._("Unable to Locate Integrity information for")." {$filename} - "._("Continuing Anyway")."</div>"; } else { if ($res['md5sum'] != md5($filedata)) { unlink($filename); return array(sprintf(_('File Integrity failed for %s - aborting'), $filename)); } } // invoke progress callback if (function_exists($progress_callback)) { $progress_callback('untar', array('module' => $modulename, 'size' => filesize($filename))); } /* We will explode the tarball in the cache directory and then once successful, remove the old module before before * moving the new one over. This way, things like removed files end up being removed instead of laying around * * TODO: save old module being replaced, if there is an old one. * */ exec("rm -rf " . $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/{$modulename}", $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not remove %s to install new version'), $amp_conf['AMPWEBROOT'] . '/admin/modules/_cache/' . $modulenam)); } exec("tar zxf " . escapeshellarg($filename) . " -C " . escapeshellarg($amp_conf['AMPWEBROOT'] . '/admin/modules/_cache/'), $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not untar %s to %s'), $filename, $amp_conf['AMPWEBROOT'] . '/admin/modules/_cache')); } exec("rm -rf " . $amp_conf['AMPWEBROOT'] . "/admin/modules/{$modulename}", $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not remove old module %s to install new version'), $amp_conf['AMPWEBROOT'] . '/admin/modules/' . $modulename)); } exec("mv " . $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/{$modulename} " . $amp_conf['AMPWEBROOT'] . "/admin/modules/{$modulename}", $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not move %s to %s'), $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/{$modulename}", $amp_conf['AMPWEBROOT'] . '/admin/modules/')); } // invoke progress_callback if (function_exists($progress_callback)) { $progress_callback('done', array('module' => $modulename)); } return true; }
function url_get_contents($url, $request, $verb = 'get', $params = array()) { $params['sv'] = 2; global $amp_conf; $verb = strtolower($verb); $contents = null; if (!$amp_conf['MODULEADMINWGET']) { $pest = new Pest($url); try { $contents = $pest->{$verb}($url . $request, $params); if (isset($pest->last_headers['x-regenerate-id'])) { $this->_regenerate_unique_id(); } return $contents; } catch (Exception $e) { freepbx_log(FPBX_LOG_ERROR, sprintf(_('Failed to get remote file, error was:'), (string) $e->getMessage())); } } $fn = $url . $request; if (empty($contents)) { $fn2 = str_replace('&', '\\&', $fn); $p = !empty($params) ? "--post-data '" . http_build_query($params) . "'" : ""; exec("wget --tries=1 --timeout=30 {$p} -O - {$fn2} 2>> /dev/null", $data_arr, $retcode); if ($retcode) { // if server isn't available for some reason should return non-zero // so we return and we don't set the flag below freepbx_log(FPBX_LOG_ERROR, sprintf(_('Failed to get remote file, mirror site may be down: %s'), $fn)); // We are here if contents were blank. It's possible that whatever we were getting were suppose to be blank // so we only auto set the WGET var if we received something so as to not false trigger. If there are issues // with content filters that this is designed to get around, we will eventually get a non-empty file which // will trigger this for now and the future. return null; } elseif (!empty($data_arr) && !$amp_conf['MODULEADMINWGET']) { $freepbx_conf =& freepbx_conf::create(); $freepbx_conf->set_conf_values(array('MODULEADMINWGET' => true), true); $nt =& notifications::create($db); $text = sprintf(_("Forced %s to true"), 'MODULEADMINWGET'); $extext = sprintf(_("The system detected a problem trying to access external server data and changed internal setting %s (Use wget For Module Admin) to true, see the tooltip in Advanced Settings for more details."), 'MODULEADMINWGET'); $nt->add_warning('freepbx', 'MODULEADMINWGET', $text, $extext, '', false, true); } $headers = get_headers_assoc($fn2); if (isset($headers['x-regenerate-id'])) { $this->_regenerate_unique_id(); } $contents = implode("\n", $data_arr); return $contents; } }
function module_download($modulename, $force = false, $progress_callback = null, $override_svn = false, $override_xml = false) { global $amp_conf; if ($time_limit = ini_get('max_execution_time')) { set_time_limit($time_limit); } // size of download blocks to fread() // basically, this controls how often progress_callback is called $download_chunk_size = 12 * 1024; // invoke progress callback if (function_exists($progress_callback)) { $progress_callback('getinfo', array('module' => $modulename)); } $res = module_getonlinexml($modulename, $override_xml); if ($res == null) { return array(_("Module not found in repository")); } $file = basename($res['location']); $filename = $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/" . $file; // if we're not forcing the download, and a file with the target name exists.. if (!$force && file_exists($filename)) { // We might already have it! Let's check the MD5. $filedata = ""; if ($fh = @fopen($filename, "r")) { while (!feof($fh)) { $filedata .= fread($fh, 8192); } fclose($fh); } if (isset($res['md5sum']) && $res['md5sum'] == md5($filedata)) { // Note, if there's no MD5 information, it will redownload // every time. Otherwise theres no way to avoid a corrupt // download // invoke progress callback if (function_exists($progress_callback)) { $progress_callback('untar', array('module' => $modulename, 'size' => filesize($filename))); } /* We will explode the tarball in the cache directory and then once successful, remove the old module before before * moving the new one over. This way, things like removed files end up being removed instead of laying around * * TODO: save old module being replaced, if there is an old one. */ exec("rm -rf " . $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/{$modulename}", $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not remove %s to install new version'), $amp_conf['AMPWEBROOT'] . '/admin/modules/_cache/' . $modulename)); } exec("tar zxf " . escapeshellarg($filename) . " -C " . escapeshellarg($amp_conf['AMPWEBROOT'] . '/admin/modules/_cache/'), $output, $exitcode); if ($exitcode != 0) { freepbx_log(FPBX_LOG_ERROR, sprintf(_("failed to open %s module archive into _cache directory."), $filename)); return array(sprintf(_('Could not untar %s to %s'), $filename, $amp_conf['AMPWEBROOT'] . '/admin/modules/_cache')); } else { // since untarring was successful, remvove the tarball so they do not accumulate if (unlink($filename) === false) { freepbx_log(FPBX_LOG_WARNING, sprintf(_("failed to delete %s from cache directory after opening module archive."), $filename)); } } exec("rm -rf " . $amp_conf['AMPWEBROOT'] . "/admin/modules/{$modulename}", $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not remove old module %s to install new version'), $amp_conf['AMPWEBROOT'] . '/admin/modules/' . $modulename)); } exec("mv " . $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/{$modulename} " . $amp_conf['AMPWEBROOT'] . "/admin/modules/{$modulename}", $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not move %s to %s'), $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/{$modulename}", $amp_conf['AMPWEBROOT'] . '/admin/modules/')); } // invoke progress_callback if (function_exists($progress_callback)) { $progress_callback('done', array('module' => $modulename)); } return true; } else { unlink($filename); } } if (!($fp = @fopen($filename, "w"))) { return array(sprintf(_("Error opening %s for writing"), $filename)); } if ($override_svn) { $url_list = array($override_svn . $res['location']); } else { $url_list = generate_module_repo_url("/modules/" . $res['location'], true); } // Check each URL until get_headers_assoc() returns something intelligible. We then use // that URL and hope the file is there, we won't check others. // $headers = false; foreach ($url_list as $u) { $headers = get_headers_assoc($u); if (!empty($headers)) { $url = $u; break; } freepbx_log(FPBX_LOG_ERROR, sprintf(_('Failed download module tarball from %s, server may be down'), $u)); } if (!$headers || !$url) { return array(sprintf(_("Unable to connect to servers from URLs provided: %s"), implode(',', $url_list))); } // TODO: do we want to make more robust past this point: // At this point we have settled on a specific URL that we can reach, if the file isn't there we won't try // other servers to check for it. The assumption is that no backup server will have it either at this point // If we wanted to make this more robust we could go back and try other servers. This code is a bit tangled // so some better factoring might help. // $totalread = 0; // invoke progress_callback if (function_exists($progress_callback)) { $progress_callback('downloading', array('module' => $modulename, 'read' => $totalread, 'total' => $headers['content-length'])); } // Check MODULEADMINWGET first so we don't execute the fopen() if set // if ($amp_conf['MODULEADMINWGET'] || !($dp = @fopen($url, 'r'))) { exec("wget --tries=1 --timeout=600 -O {$filename} {$url} 2> /dev/null", $filedata, $retcode); if ($retcode != 0) { return array(sprintf(_("Error opening %s for reading"), $url)); } else { if (!($dp = @fopen($filename, 'r'))) { return array(sprintf(_("Error opening %s for reading"), $url)); } } } $filedata = ''; while (!feof($dp)) { $data = fread($dp, $download_chunk_size); $filedata .= $data; $totalread += strlen($data); if (function_exists($progress_callback)) { $progress_callback('downloading', array('module' => $modulename, 'read' => $totalread, 'total' => $headers['content-length'])); } } fwrite($fp, $filedata); fclose($dp); fclose($fp); if (is_readable($filename) !== TRUE) { return array(sprintf(_('Unable to save %s'), $filename)); } // Check the MD5 info against what's in the module's XML if (!isset($res['md5sum']) || empty($res['md5sum'])) { //echo "<div class=\"error\">"._("Unable to Locate Integrity information for")." {$filename} - "._("Continuing Anyway")."</div>"; } else { if ($res['md5sum'] != md5($filedata)) { unlink($filename); return array(sprintf(_('File Integrity failed for %s - aborting'), $filename)); } } // invoke progress callback if (function_exists($progress_callback)) { $progress_callback('untar', array('module' => $modulename, 'size' => filesize($filename))); } /* We will explode the tarball in the cache directory and then once successful, remove the old module before before * moving the new one over. This way, things like removed files end up being removed instead of laying around * * TODO: save old module being replaced, if there is an old one. * */ exec("rm -rf " . $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/{$modulename}", $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not remove %s to install new version'), $amp_conf['AMPWEBROOT'] . '/admin/modules/_cache/' . $modulename)); } exec("tar zxf " . escapeshellarg($filename) . " -C " . escapeshellarg($amp_conf['AMPWEBROOT'] . '/admin/modules/_cache/'), $output, $exitcode); if ($exitcode != 0) { freepbx_log(FPBX_LOG_ERROR, sprintf(_("failed to open %s module archive into _cache directory."), $filename)); return array(sprintf(_('Could not untar %s to %s'), $filename, $amp_conf['AMPWEBROOT'] . '/admin/modules/_cache')); } else { // since untarring was successful, remvove the tarball so they do not accumulate if (unlink($filename) === false) { freepbx_log(FPBX_LOG_WARNING, sprintf(_("failed to delete %s from cache directory after opening module archive."), $filename)); } } exec("rm -rf " . $amp_conf['AMPWEBROOT'] . "/admin/modules/{$modulename}", $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not remove old module %s to install new version'), $amp_conf['AMPWEBROOT'] . '/admin/modules/' . $modulename)); } exec("mv " . $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/{$modulename} " . $amp_conf['AMPWEBROOT'] . "/admin/modules/{$modulename}", $output, $exitcode); if ($exitcode != 0) { return array(sprintf(_('Could not move %s to %s'), $amp_conf['AMPWEBROOT'] . "/admin/modules/_cache/{$modulename}", $amp_conf['AMPWEBROOT'] . '/admin/modules/')); } // invoke progress_callback if (function_exists($progress_callback)) { $progress_callback('done', array('module' => $modulename)); } return true; }