Newer
Older

cedric@yterium.com
a validé
<?php
use Spip\Archiver\SpipArchiver;

cedric@yterium.com
a validé
/***************************************************************************\
* SPIP, Système de publication pour l'internet *

cedric@yterium.com
a validé
* *
* Copyright © avec tendresse depuis 2001 *
* Arnaud Martin, Antoine Pitrou, Philippe Rivière, Emmanuel Saint-James *

cedric@yterium.com
a validé
* *
* Ce programme est un logiciel libre distribué sous licence GNU/GPL. *

cedric@yterium.com
a validé
\***************************************************************************/
/**
* Gestion de l'action ajouter_documents
*
* @package SPIP\Medias\Action

cedric@yterium.com
a validé
return;
}

cedric@yterium.com
a validé
include_spip('inc/getdocument');
include_spip('inc/documents');

cedric@yterium.com
a validé
include_spip('inc/choisir_mode_document'); // compat core
include_spip('inc/renseigner_document');

cedric@yterium.com
a validé
/**
* Ajouter des documents
*
* @param int $id_document
* Document à remplacer, ou pour une vignette, l'id_document de maman
* Tableau de tableaux de propriétés pour chaque document à insérer
* @param string $objet
* Objet auquel associer le document
* @param int $id_objet
* @param string $mode
* Mode par défaut si pas precisé pour le document

cedric@yterium.com
a validé
function action_ajouter_documents_dist($id_document, $files, $objet, $id_objet, $mode) {
$ajouter_un_document = charger_fonction('ajouter_un_document', 'action');

cedric@yterium.com
a validé

cedric@yterium.com
a validé
// on ne peut mettre qu'un seul document a la place d'un autre ou en vignette d'un autre

cedric@yterium.com
a validé
if (intval($id_document)) {

cedric@yterium.com
a validé
$ajoutes[] = $ajouter_un_document($id_document, reset($files), $objet, $id_objet, $mode);

cedric@yterium.com
a validé
} else {
foreach ($files as $file) {

cedric@yterium.com
a validé
$ajoutes[] = $ajouter_un_document('new', $file, $objet, $id_objet, $mode);
}

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
return $ajoutes;

cedric@yterium.com
a validé
}
/**

cedric@yterium.com
a validé
* Ajouter un document (au format $_FILES)

cedric@yterium.com
a validé
*
* Document à remplacer, ou pour une vignette, l'id_document de maman

cedric@yterium.com
a validé
*
* - string tmp_name : source sur le serveur
* - string name : nom du fichier envoye
* - bool titrer : donner ou non un titre a partir du nom du fichier
* - bool distant : pour utiliser une source distante sur internet
* - string mode : vignette|image|documents|choix
* Mode par défaut si pas precisé pour le document
*
* - int : l'id_document ajouté (opération réussie)
* - string : une erreur s'est produit, la chaine est le message d'erreur

cedric@yterium.com
a validé
*/

cedric@yterium.com
a validé
function action_ajouter_un_document_dist($id_document, $file, $objet, $id_objet, $mode) {

marcimat@rezo.net
a validé

cedric@yterium.com
a validé
$source = $file['tmp_name'];
$nom_envoye = $file['name'];
// passer en minuscules le nom du fichier, pour eviter les collisions
// si le file system fait la difference entre les deux il ne detectera
// pas que Toto.pdf et toto.pdf
// et on aura une collision en cas de changement de file system
$file['name'] = strtolower(translitteration($file['name']));

cedric@yterium.com
a validé
// Sécurité : si jamais il existe deja une entrée dans la BDD avec ce chemin de document, remettre le document dans tmp, ce qui permettra ensuite qu'il soit dupliqué, et qu'il n'y ait pas deux entrées en base avec la même ligne 'fichier'.
// Cela n'arrive que si $file indique un document qui se trouve déjà dans IMG.
while (sql_getfetsel('fichier', 'spip_documents', 'fichier=' . sql_quote(set_spip_doc($file['tmp_name'])))) {
$tmp = tempnam(is_dir(_DIR_TRANSFERT) ? _DIR_TRANSFERT : _DIR_TMP, $file['tmp_name']);
if (deplacer_fichier_upload($file['tmp_name'], $tmp)) {
$file['tmp_name'] = $tmp;
} else {
spip_log('Erreur lors de la tenative de copie de ' . $file['tmp_name'] . ' en ' . $tmp, 'medias' . _LOG_ERREUR);
break;
}
}

cedric@yterium.com
a validé
// Pouvoir definir dans mes_options.php que l'on veut titrer tous les documents par d?faut

cedric@yterium.com
a validé
if (!defined('_TITRER_DOCUMENTS')) {
define('_TITRER_DOCUMENTS', false);
}

cedric@yterium.com
a validé
$titrer = $file['titrer'] ?? _TITRER_DOCUMENTS;
$mode = ((isset($file['mode']) && $file['mode']) ? $file['mode'] : $mode);

cedric@yterium.com
a validé
include_spip('inc/modifier');
isset($file['distant']) && $file['distant'] && !in_array($mode, ['choix', 'auto', 'image', 'document'])
) {
spip_log("document distant $source accepte sans verification, mode=$mode", 'medias' . _LOG_INFO_IMPORTANTE);

cedric@yterium.com
a validé
include_spip('inc/distant');
$file['tmp_name'] = _DIR_RACINE . copie_locale($source);
$source = $file['tmp_name'];
unset($file['distant']);
}

cedric@yterium.com
a validé

cedric@yterium.com
a validé
// Documents distants : pas trop de verifications bloquantes, mais un test
// via une requete HEAD pour savoir si la ressource existe (non 404), si le
// content-type est connu, et si possible recuperer la taille, voire plus.
if (isset($file['distant']) && $file['distant']) {
return _T('medias:erreur_chemin_distant', ['nom' => $source]);

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
include_spip('inc/distant');
$source = str_replace(["'", '"', '<'], ['%27', '%22', '%3C'], $source);

cedric@yterium.com
a validé
if (is_array($a = renseigner_source_distante($source))) {
$champs = $a;

cedric@yterium.com
a validé
# NB: dans les bonnes conditions (fichier autorise et pas trop gros)
# $a['copie_locale'] est une copie locale du fichier
// voir si le document a besoin d'un nettoyage et le cas echeant relire ses infos apres
if (!empty($champs['copie_locale']) && file_exists($champs['copie_locale'])) {
$res_sanitize = sanitizer_document($champs['copie_locale'], $champs['extension']);
$infos = renseigner_taille_dimension_image($champs['copie_locale'], $champs['extension']);
$infos = renseigner_taille_dimension_image($champs['fichier'], $champs['extension'], true);
}

cedric@yterium.com
a validé

cedric@yterium.com
a validé
// on ignore erreur eventuelle sur $infos car on est distant, ca ne marche pas forcement

cedric@yterium.com
a validé
if (is_array($infos)) {
foreach ($infos as $k => $v) {
$champs[$k] = $v;
}
}

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
unset($champs['type_image']);

cedric@yterium.com
a validé
} // on ne doit plus arriver ici, car l'url distante a ete verifiee a la saisie !

cedric@yterium.com
a validé
else {
spip_log("Echec du lien vers le document $source, abandon");

cedric@yterium.com
a validé

cedric@yterium.com
a validé
return $a; // message d'erreur

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
} else { // pas distant

cedric@yterium.com
a validé

cedric@yterium.com
a validé
$champs['titre'] = '';

cedric@yterium.com
a validé
if ($titrer) {

cedric@yterium.com
a validé
if ($titrer_document = charger_fonction('titrer_document', 'inc', true)) {
$champs['titre'] = $titrer_document($nom_envoye);
$titre = substr(
(string) $nom_envoye,
0,
strrpos((string) $nom_envoye, '.')
); // Enlever l'extension du nom du fichier

cedric@yterium.com
a validé
$titre = preg_replace(',[[:punct:][:space:]]+,u', ' ', $titre);
$champs['titre'] = preg_replace(',\.([^.]+)$,', '', (string) $titre);

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
if (!is_array($fichier = fixer_fichier_upload($file, $mode))) {
$fichier : _T('medias:erreur_upload_type_interdit', ['nom' => $file['name']]);

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
$champs['inclus'] = $fichier['inclus'];
$champs['extension'] = $fichier['extension'];
$champs['fichier'] = $fichier['fichier'];

cedric@yterium.com
a validé
/**
* Récupère les informations du fichier
* -* largeur
* -* hauteur
* -* type_image
* -* taille
* -* ses metadonnées si une fonction de metadatas/ est présente
*/

cedric@yterium.com
a validé
$infos = renseigner_taille_dimension_image($champs['fichier'], $champs['extension']);
if (is_string($infos)) {

marcimat@rezo.net
a validé
// c'est un message d'erreur !

cedric@yterium.com
a validé
return $infos;

marcimat@rezo.net
a validé
}
// lorsqu’une image arrive avec une mauvaise extension par rapport au mime type, adapter.
// Exemple : si extension .jpg mais le contenu est un png
if (!empty($infos['type_image']) && $infos['type_image'] !== $champs['extension']) {
spip_log(
'Image `' . $file['name'] . '` mauvaise extension. Correcte : ' . $infos['type_image'],
'medias' . _LOG_INFO
);

cedric@yterium.com
a validé
$subdir = determiner_sous_dossier_document($infos['type_image'], $file['name'] . '.' . $infos['type_image'], $mode);
$new = copier_document(
$infos['type_image'],
$file['name'] . '.' . $infos['type_image'],
$champs['fichier'],
$subdir
);

marcimat@rezo.net
a validé
if ($new) {
supprimer_fichier($champs['fichier']);
$champs['fichier'] = $new;
$champs['extension'] = $infos['type_image'];
$infos = renseigner_taille_dimension_image($champs['fichier'], $champs['extension']);
if (is_string($infos)) {
// c'est un message d'erreur !
return $infos;
}
spip_log('> Image `' . $file['name'] . '` renommée en : ' . basename($champs['fichier']), 'medias' . _LOG_INFO);
} else {
spip_log(
'! Image `' . $file['name'] . '` non renommée en extension : ' . $champs['extension'],
'medias' . _LOG_INFO_IMPORTANTE
);

marcimat@rezo.net
a validé
}
}

cedric@yterium.com
a validé
// voir si le document a besoin d'un nettoyage et le cas echeant relire ses infos apres
if (sanitizer_document($champs['fichier'], $champs['extension'])) {
$infos = renseigner_taille_dimension_image($champs['fichier'], $champs['extension']);
}

cedric@yterium.com
a validé
$champs = array_merge($champs, $infos);

cedric@yterium.com
a validé

cedric@yterium.com
a validé
// Si mode == 'choix', fixer le mode image/document
if (in_array($mode, ['choix', 'auto'])) {

cedric@yterium.com
a validé
$choisir_mode_document = charger_fonction('choisir_mode_document', 'inc');

cedric@yterium.com
a validé
$mode = $choisir_mode_document($champs, $champs['inclus'] == 'image', $objet);

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
$champs['mode'] = $mode;

cedric@yterium.com
a validé
// ne pas tester les tailles max de logos et documents définies dans les defines _MAX_SIZE, _MAX_WIDTH & _MAX_HEIGHT
// lors de la migration des logos en base cf logo_migrer_en_base()
if (!isset($GLOBALS['logo_migrer_en_base'])) {
if (($test = verifier_taille_document_acceptable($champs)) !== true) {
spip_unlink($champs['fichier']);

cedric@yterium.com
a validé
return $test; // erreur sur les dimensions du fichier
}

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
unset($champs['type_image']);
unset($champs['inclus']);
$champs['fichier'] = set_spip_doc($champs['fichier']);
}

cedric@yterium.com
a validé
// si le media est pas renseigne, le faire, en fonction de l'extension

cedric@yterium.com
a validé
if (!isset($champs['media'])) {
$champs['media'] = sql_getfetsel(
'media_defaut',
'spip_types_documents',
'extension=' . sql_quote($champs['extension'])
);

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé

cedric@yterium.com
a validé
// lier le parent si necessaire
// attention au cas particulier du site 0 utilisé pour le logo du site
if ($objet && (($id_objet = intval($id_objet)) || in_array($objet, ['site', 'rubrique']))) {

cedric@yterium.com
a validé
$champs['parents'][] = "$objet|$id_objet";

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
// "mettre a jour un document" si on lui
// passe un id_document

cedric@yterium.com
a validé
if ($id_document = intval($id_document)) {

cedric@yterium.com
a validé
unset($champs['titre']); // garder le titre d'origine
unset($champs['date']); // garder la date d'origine
unset($champs['descriptif']); // garder la desc d'origine
// unset($a['distant']); # on peut remplacer un doc statique par un doc distant
// unset($a['mode']); # on peut remplacer une image par un document ?

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
include_spip('action/editer_document');

cedric@yterium.com
a validé
// Installer le document dans la base

cedric@yterium.com
a validé
if (!$id_document) {
if ($id_document = document_inserer()) {
spip_log(
'ajout du document ' . $file['tmp_name'] . ' ' . $file['name'] . " (M '$mode' T '$objet' L '$id_objet' D '$id_document')",
'medias'
);

cedric@yterium.com
a validé
} else {
'Echec document_inserer() du document ' . $file['tmp_name'] . ' ' . $file['name'] . " (M '$mode' T '$objet' L '$id_objet' D '$id_document')",

cedric@yterium.com
a validé
}
}
if (!$id_document) {
return _T('medias:erreur_insertion_document_base', ['fichier' => '<em>' . $file['name'] . '</em>']);

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
document_modifier($id_document, $champs);

cedric@yterium.com
a validé
// permettre aux plugins de faire des modifs a l'ajout initial
// ex EXIF qui tourne les images si necessaire
// Ce plugin ferait quand même mieux de se placer dans metadata/jpg.php

cedric@yterium.com
a validé
'table' => 'spip_documents', // compatibilite
'table_objet' => 'documents',
'spip_table_objet' => 'spip_documents',

cedric@yterium.com
a validé
'type' => 'document',

cedric@yterium.com
a validé
'id_objet' => $id_document,
'champs' => array_keys($champs),
'serveur' => '', // serveur par defaut, on ne sait pas faire mieux pour le moment
'action' => 'ajouter_document',
'operation' => 'ajouter_document', // compat <= v2.0

cedric@yterium.com
a validé
);

cedric@yterium.com
a validé
return $id_document;

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
/**
* Sous-repertoire dans lequel on stocke le document
* en regle general $ext/ sauf pour les logo
* @return mixed
*/
function determiner_sous_dossier_document($ext, $fichier, $mode) {
// si mode un logoxx on met dans logo/

cedric@yterium.com
a validé
}
return $ext;
}

cedric@yterium.com
a validé
/**
* Vérifie la possibilité d'uploader une extension

cedric@yterium.com
a validé
*
* Vérifie aussi si l'extension est autorisée pour le mode demandé
* si on connait le mode à ce moment là
*
* @param string $source
* Nom du fichier
* @param string $mode
* Mode d'inclusion du fichier, si connu
* @return array|bool|string
*
* - array : extension acceptée (tableau descriptif).
* Avec un index 'autozip' si il faut zipper
* - false ou message d'erreur si l'extension est refusée

cedric@yterium.com
a validé
*/

cedric@yterium.com
a validé
function verifier_upload_autorise($source, $mode = '') {
$infos = ['fichier' => $source];
preg_match(',\.([a-z0-9]+)(\?.*)?$,i', $source, $match)
&& ($ext = $match[1])

cedric@yterium.com
a validé
) {
$ext = corriger_extension(strtolower($ext));
if (
$res = sql_fetsel(
'extension,inclus,media_defaut as media',
'spip_types_documents',
'extension=' . sql_quote($ext) . " AND upload='oui'"
)
) {

cedric@yterium.com
a validé
$infos = array_merge($infos, $res);
}

cedric@yterium.com
a validé
if (!$res) {
if (
$res = sql_fetsel(
'extension,inclus,media_defaut as media',
'spip_types_documents',
"extension='zip' AND upload='oui'"
)
) {

cedric@yterium.com
a validé
$infos = array_merge($infos, $res);
$res['autozip'] = true;
}
}
// verifier en fonction du mode si une fonction est proposee
if ($verifier_document_mode = charger_fonction('verifier_document_mode_' . $mode, 'inc', true)) {
$check = $verifier_document_mode($infos); // true ou message d'erreur sous forme de chaine

cedric@yterium.com
a validé
if ($check !== true) {

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé

cedric@yterium.com
a validé
spip_log("Upload $source interdit ($res)", _LOG_INFO_IMPORTANTE);

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
/**

cedric@yterium.com
a validé
*
* - le document existe et n'est pas de taille 0 ?

cedric@yterium.com
a validé
* - interdit a l'upload ?
* - quelle extension dans spip_types_documents ?
* - est-ce "inclus" comme une image ?

cedric@yterium.com
a validé
*

cedric@yterium.com
a validé
*
* @param array $file
* Au format $_FILES
* @param string $mode
* Mode d'inclusion du fichier, si connu
* @return array|string

cedric@yterium.com
a validé
*/

cedric@yterium.com
a validé
function fixer_fichier_upload($file, $mode = '') {

cedric@yterium.com
a validé
* On vérifie que le fichier existe et qu'il contient quelque chose

cedric@yterium.com
a validé
if (is_array($row = verifier_upload_autorise($file['name'], $mode))) {

cedric@yterium.com
a validé
$subdir = determiner_sous_dossier_document($row['extension'], $file['name'], $mode);

cedric@yterium.com
a validé
if (!isset($row['autozip'])) {

cedric@yterium.com
a validé
$row['fichier'] = copier_document($row['extension'], $file['name'], $file['tmp_name'], $subdir);
/**
* On vérifie que le fichier a une taille
* si non, on le supprime et on affiche une erreur
*/

cedric@yterium.com
a validé
if ($row['fichier'] && (!$taille = @intval(filesize(get_spip_doc($row['fichier']))))) {
spip_log('Echec copie du fichier ' . $file['tmp_name'] . ' (taille de fichier indéfinie)');
return _T('medias:erreur_copie_fichier', ['nom' => $file['tmp_name']]);

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
}
// creer un zip comme demande
// pour encapsuler un fichier dont l'extension n'est pas supportee
unset($row['autozip']);

cedric@yterium.com
a validé
$ext = 'zip';
if (!$tmp_dir = tempnam(_DIR_TMP, 'tmp_upload')) {
return false;
}
include_spip('inc/charsets');
$tmp = $tmp_dir . '/' . translitteration($file['name']);
// conserver l'extension dans le nom de fichier, par exemple toto.js => toto.js.zip
$file['name'] .= '.' . $ext;
// deplacer le fichier tmp_name dans le dossier tmp
deplacer_fichier_upload($file['tmp_name'], $tmp, true);
$archive = new SpipArchiver($source);
$res = $archive->emballer([$tmp]);
effacer_repertoire_temporaire($tmp_dir);
if (!$res) {
spip_log("Echec creation du zip $source", 'medias' . _LOG_ERREUR);
return _T('medias:erreur_ecriture_fichier');
}

cedric@yterium.com
a validé
$row['fichier'] = copier_document($row['extension'], $file['name'], $source, $subdir);
spip_unlink($source);
/**
* On vérifie que le fichier a une taille
* si non, on le supprime et on affiche une erreur
*/
if ($row['fichier'] && (!$taille = @intval(filesize(get_spip_doc($row['fichier']))))) {
spip_log('Echec copie du fichier ' . $file['tmp_name'] . ' (taille de fichier indéfinie)');
spip_unlink(get_spip_doc($row['fichier']));
return _T('medias:erreur_copie_fichier', ['nom' => $file['tmp_name']]);

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé
return $row;

cedric@yterium.com
a validé
}
/**
* Verifier si le fichier respecte les contraintes de tailles

cedric@yterium.com
a validé
*

cedric@yterium.com
a validé
function verifier_taille_document_acceptable(&$infos) {
$is_logo = in_array($infos['mode'], ['logoon', 'logooff']);

cedric@yterium.com
a validé
$verifier_taille_document_acceptable = charger_fonction('verifier_taille_document_acceptable', 'inc');
$res = $verifier_taille_document_acceptable($infos, $is_logo);

cedric@yterium.com
a validé
// si erreur, on arrete la
if ($res !== true) {
return $res;

cedric@yterium.com
a validé
}
// verifier en fonction du mode si une fonction est proposee
if ($verifier_document_mode = charger_fonction('verifier_document_mode_' . $infos['mode'], 'inc', true)) {

cedric@yterium.com
a validé
}

cedric@yterium.com
a validé

cedric@yterium.com
a validé
return true;