/** * Charger un tgz à partir d'un tableau d'options descriptives * * @param array $quoi * Tableau d'options * @return array|bool|int|string * En cas de réussite, Tableau décrivant le zip, avec les index suivant : * - files : la liste des fichiers présents dans le zip, * - size : la taille décompressée * - compressed_size : la taille compressée * - dirname : répertoire où les fichiers devront être décompréssés * - tmpname : répertoire temporaire où les fichiers sont décompressés * - target : cible sur laquelle décompresser les fichiers... */ function teleporter_http_charger_tgz($quoi = array()) { if (!$quoi) { return false; } foreach (array('remove' => '', 'rename' => array(), 'edit' => array(), 'root_extract' => false, 'tmp' => sous_repertoire(_DIR_CACHE, 'chargeur')) as $opt => $def) { isset($quoi[$opt]) || ($quoi[$opt] = $def); } if (!@file_exists($fichier = $quoi['fichier'])) { return 0; } include_spip('inc/pcltar'); $racine = ''; if ($list = PclTarList($fichier)) { $racine = http_deballe_recherche_racine($list); $quoi['remove'] = $racine; } else { spip_log('charger_decompresser erreur lecture liste tar ' . PclErrorString() . ' pour paquet: ' . $quoi['archive'], "teleport" . _LOG_ERREUR); return PclErrorString(); } // si pas de racine commune, reprendre le nom du fichier zip // en lui enlevant la racine h+md5 qui le prefixe eventuellement // cf action/charger_plugin L74 if (!strlen($nom = basename($racine))) { $nom = preg_replace(",^h[0-9a-f]{8}-,i", "", basename($fichier, '.zip')); } $dir_export = $quoi['root_extract'] ? $quoi['dest'] : $quoi['dest'] . $nom; $dir_export = rtrim($dir_export, '/') . '/'; $tmpname = $quoi['tmp'] . $nom . '/'; // choisir la cible selon si on veut vraiment extraire ou pas $target = $quoi['extract'] ? $dir_export : $tmpname; // ici, il faut vider le rep cible si il existe deja, non ? if (is_dir($target)) { supprimer_repertoire($target); } $ok = PclTarExtract($fichier, $target, $quoi['remove']); if ($ok == 0) { spip_log('charger_decompresser erreur tar ' . PclErrorString() . ' pour paquet: ' . $quoi['archive'], "teleport" . _LOG_ERREUR); return PclErrorString(); } spip_log('charger_decompresser OK pour paquet: ' . $quoi['archive'], "teleport"); $size = $compressed_size = 0; $removex = ',^' . preg_quote($quoi['remove'], ',') . ','; foreach ($list as $a => $f) { $size += $f['size']; $compressed_size += $f['compressed_size']; $list[$a] = preg_replace($removex, '', $f['filename']); } // Indiquer par un fichier install.log // a la racine que c'est chargeur qui a installe ce plugin ecrire_fichier($target . 'install.log', "installation: charger_plugin\n" . "date: " . gmdate('Y-m-d\\TH:i:s\\Z', time()) . "\n" . "source: " . $quoi['archive'] . "\n"); return array('files' => $list, 'size' => $size, 'compressed_size' => $compressed_size, 'dirname' => $dir_export, 'tmpname' => $tmpname, 'target' => $target); }
/** * Télécharge un paquet * * Supprime les fichiers obsolètes (si présents) * * @param int|array $id_or_row * Identifiant du paquet ou description ligne SQL du paquet * @param string $dest_ancien * Chemin vers l'ancien répertoire (pour les mises à jour par VCS) * @return bool|array * False si erreur. * Tableau de 2 index sinon : * - dir : Chemin du paquet téléchargé depuis la racine * - dossier : Chemin du paquet téléchargé, depuis _DIR_PLUGINS */ public function get_paquet_id($id_or_row, $dest_ancien = "") { // on peut passer direct le row sql... if (!is_array($id_or_row)) { $i = sql_fetsel('*', 'spip_paquets', 'id_paquet=' . sql_quote($id_or_row)); } else { $i = $id_or_row; } unset($id_or_row); if ($i['nom_archive'] and $i['id_depot']) { $this->log("Recuperer l'archive : " . $i['nom_archive']); // on récupère les informations intéressantes du dépot : // - url des archives // - éventuellement : type de serveur (svn, git) et url de la racine serveur (svn://..../) $adresses = sql_fetsel(array('url_archives', 'type', 'url_serveur'), 'spip_depots', 'id_depot=' . sql_quote($i['id_depot'])); if ($adresses and $adresse = $adresses['url_archives']) { // destination : auto/prefixe/version (sinon auto/nom_archive/version) $prefixe = sql_getfetsel('pl.prefixe', array('spip_paquets AS pa', 'spip_plugins AS pl'), array('pa.id_plugin = pl.id_plugin', 'pa.id_paquet=' . sql_quote($i['id_paquet']))); // prefixe $base = $prefixe ? strtolower($prefixe) : substr($i['nom_archive'], 0, -4); // enlever .zip ... // prefixe/version $dest_future = $base . '/v' . denormaliser_version($i['version']); // Nettoyer les vieux formats dans auto/ if ($this->tester_repertoire_destination_ancien_format(_DIR_PLUGINS_AUTO . $base)) { supprimer_repertoire(_DIR_PLUGINS_AUTO . $base); } // l'url est différente en fonction du téléporteur $teleporteur = $this->choisir_teleporteur($adresses['type']); if ($teleporteur == 'http') { $url = $adresse . '/' . $i['nom_archive']; $dest = $dest_future; } else { $url = $adresses['url_serveur'] . '/' . $i['src_archive']; $dest = $dest_ancien ? $dest_ancien : $dest_future; } // on recupere la mise a jour... include_spip('action/teleporter'); $teleporter_composant = charger_fonction('teleporter_composant', 'action'); $ok = $teleporter_composant($teleporteur, $url, _DIR_PLUGINS_AUTO . $dest); if ($ok === true) { // pour une mise à jour via VCS, il faut rebasculer sur le nouveau nom de repertoire if ($dest != $dest_future) { rename(_DIR_PLUGINS_AUTO . $dest, _DIR_PLUGINS_AUTO . $dest_future); } return array('dir' => _DIR_PLUGINS_AUTO . $dest, 'dossier' => 'auto/' . $dest); } $this->err($ok); $this->log("Téléporteur en erreur : " . $ok); } else { $this->log("Aucune adresse pour le dépot " . $i['id_depot']); } } return false; }
/** * Télécharge un paquet * * Supprime les fichiers obsolètes (si présents) * * @param int|array $id_or_row * Identifiant du paquet ou description ligne SQL du paquet * @return bool|array * False si erreur. * Tableau de 2 index sinon : * - dir : Chemin du paquet téléchargé depuis la racine * - dossier : Chemin du paquet téléchargé, depuis _DIR_PLUGINS */ function get_paquet_id($id_or_row) { // on peut passer direct le row sql... if (!is_array($id_or_row)) { $i = sql_fetsel('*', 'spip_paquets', 'id_paquet=' . sql_quote($id_or_row)); } else { $i = $id_or_row; } unset($id_or_row); if ($i['nom_archive'] and $i['id_depot']) { $this->log("Recuperer l'archive : " . $i['nom_archive']); if ($adresse = sql_getfetsel('url_archives', 'spip_depots', 'id_depot=' . sql_quote($i['id_depot']))) { $zip = $adresse . '/' . $i['nom_archive']; // destination : auto/prefixe/version (sinon auto/nom_archive/version) $prefixe = sql_getfetsel('pl.prefixe', array('spip_paquets AS pa', 'spip_plugins AS pl'), array('pa.id_plugin = pl.id_plugin', 'pa.id_paquet=' . sql_quote($i['id_paquet']))); // prefixe $base = $prefixe ? strtolower($prefixe) : substr($i['nom_archive'], 0, -4); // enlever .zip ... // prefixe/version $dest = $base . '/v' . denormaliser_version($i['version']); // si on tombe sur un auto/X ayant des fichiers (et pas uniquement des dossiers) // ou un dossier qui ne commence pas par 'v' // c'est que auto/X n'était pas chargé avec SVP // ce qui peut arriver lorsqu'on migre de SPIP 2.1 à 3.0 // dans ce cas, on supprime auto X pour mettre notre nouveau paquet. $ecraser_base = false; if (is_dir(_DIR_PLUGINS_AUTO . $base)) { $base_files = scandir(_DIR_PLUGINS_AUTO . $base); if (is_array($base_files)) { $base_files = array_diff($base_files, array('.', '..')); foreach ($base_files as $f) { if ($f[0] != '.' and $f[0] != 'v' or $f[0] != '.' and !is_dir(_DIR_PLUGINS_AUTO . $base . '/' . $f)) { // commence par v mais pas repertoire $ecraser_base = true; break; } } } } if ($ecraser_base) { supprimer_repertoire(_DIR_PLUGINS_AUTO . $base); } // on recupere la mise a jour... include_spip('action/teleporter'); $teleporter_composant = charger_fonction('teleporter_composant', 'action'); $ok = $teleporter_composant('http', $zip, _DIR_PLUGINS_AUTO . $dest); if ($ok === true) { return array('dir' => _DIR_PLUGINS_AUTO . $dest, 'dossier' => 'auto/' . $dest); } $this->err($ok); $this->log("Téléporteur en erreur : " . $ok); } else { $this->log("Aucune adresse pour le dépot " . $i['id_depot']); } } return false; }
/** * Suppression complete d'un repertoire. * * @link http://www.php.net/manual/en/function.rmdir.php#92050 * * @param string $dir Chemin du repertoire * @return bool Suppression reussie. */ function supprimer_repertoire($dir) { if (!file_exists($dir)) { return true; } if (!is_dir($dir) || is_link($dir)) { return @unlink($dir); } foreach (scandir($dir) as $item) { if ($item == '.' || $item == '..') { continue; } if (!supprimer_repertoire($dir . "/" . $item)) { @chmod($dir . "/" . $item, 0777); if (!supprimer_repertoire($dir . "/" . $item)) { return false; } } } return @rmdir($dir); }
/** * Déplace un répertoire pour libérer l'emplacement. * * Si le répertoire donné existe, le déplace dans un répertoire de backup. * Si ce backup existe déjà, il est supprimé auparavant. * Retourne le nouveau chemin du répertoire. * * @param string $dest * Chemin du répertoire à déplacer * @return string * Nouveau chemin du répertoire s'il existait, * Chaîne vide sinon **/ function teleporter_nettoyer_vieille_version($dest) { $old = ""; if (is_dir($dest)) { $dir = dirname($dest); $base = basename($dest); $old = "{$dir}/.{$base}.bck"; if (is_dir($old)) { supprimer_repertoire($old); } rename($dest, $old); } return $old; }
function supprimer_repertoire($dir) { $current_dir = opendir($dir); while ($entryname = readdir($current_dir)) { if (is_dir("{$dir}/{$entryname}") and ($entryname != "." and $entryname != "..")) { supprimer_repertoire("{$dir}/{$entryname}"); } elseif ($entryname != "." and $entryname != "..") { unlink("{$dir}/{$entryname}"); } } //Fin tant que closedir($current_dir); rmdir(${dir}); }