Exporter des fichiers vers Amazon S3 avec PHP : guide complet
Pour exporter un fichier local vers Amazon S3 depuis PHP, installez le SDK AWS et appelez
putObject avec un SourceFile. Ce guide vous permet de créer un
script CLI qui stocke des objets privés avec des métadonnées et un chiffrement côté serveur,
signale les échecs par son code de sortie et prend en charge les téléversements multipart.
Vous téléchargerez également l’objet indépendamment pour vérifier que S3 a reçu exactement les
mêmes octets.
Prérequis et configuration
Utilisez un shell Bash sous Linux avec PHP, Composer 2 et AWS CLI v2 installés. Les exemples ont été testés avec PHP 8.5.10, Composer 2.10.3, AWS CLI 2.37.10 et le SDK AWS pour PHP 3.399.2. PHP 8.5 est une branche de versions maintenue ; utilisez sa version corrective actuelle pour les nouvelles installations. Il s’agit des versions testées, et non des versions minimales requises par le SDK.
Le SDK nécessite PHP 8.1 ou une version ultérieure et SimpleXML.
Ce tutoriel utilise également les extensions cURL et OpenSSL de PHP pour HTTPS. Installez les outils
manquants à l’aide du guide d’installation de PHP, des
instructions de téléchargement de Composer et des
instructions d’installation d’AWS CLI v2.
L’outil GNU cmp, utilisé pour comparer les
fichiers, est fourni par le paquet GNU Diffutils.
Avant de créer les fichiers du projet, vérifiez chaque prérequis :
(
for tool in php composer aws cmp; do
if ! command -v "$tool" >/dev/null 2>&1; then
printf 'Missing prerequisite: %s\n' "$tool" >&2
exit 1
fi
done
php -r 'foreach (["simplexml", "curl", "openssl"] as $extension) {
if (!extension_loaded($extension)) {
fwrite(STDERR, "Missing PHP extension: $extension\n"); exit(1);
}
}'
)
Installer le SDK AWS pour PHP
Travaillez dans un nouveau répertoire vide, en dehors du répertoire web public de votre application.
Enregistrez ce contenu dans composer.json ; ne remplacez pas le manifeste d’une
application existante :
{
"require": {
"aws/aws-sdk-php": "3.399.2"
}
}
Installez la version testée du SDK dans le dossier vendor/ de ce répertoire :
COMPOSER=composer.json COMPOSER_VENDOR_DIR=vendor \
composer install --no-interaction --no-plugins --no-scripts
Conservez le fichier composer.lock généré pour assurer des installations
reproductibles. Si l’installation échoue, corrigez le problème de prérequis ou de réseau signalé,
puis relancez la même commande dans ce répertoire. Vous n’avez pas besoin de supprimer le manifeste
ni le fichier de verrouillage. Le
guide d’utilisation de base de Composer explique comment le fichier
de verrouillage fixe les versions des dépendances.
Configurer les informations d’accès AWS
Utilisez un profil AWS existant disposant des autorisations nécessaires. La CLI et le SDK prennent tous deux en charge le fournisseur d’informations d’accès partagées. Choisissez le profil et la région de votre bucket, puis vérifiez le compte avant de téléverser :
export AWS_PROFILE=default
export AWS_DEFAULT_REGION=us-east-1
aws sts get-caller-identity --query Account --output text
Remplacez default et us-east-1 par vos propres valeurs.
Si les informations d’accès ont expiré, renouvelez votre session autorisée avant de continuer.
Les informations d’accès définies dans l’environnement ont priorité sur les profils ; si le compte
n’est pas celui attendu, vérifiez qu’aucun jeu d’informations d’accès n’a été exporté par
inadvertance. Ne placez jamais de clés d’accès dans le fichier PHP. Pour les applications hébergées
sur AWS, préférez un rôle IAM destiné à la charge de travail à des clés de longue durée.
Créer un bucket S3 simple
Le script utilise un bucket S3 à usage général existant et privé. Si vous en avez besoin, demandez
à l’administrateur de votre bucket de suivre le
guide de création de buckets d’AWS.
Gardez Block Public Access activé et réglez Object Ownership sur Bucket owner enforced. Utilisez la
région réelle du bucket dans AWS_DEFAULT_REGION ; l’administration du bucket est distincte
du script d’export.
Pour les commandes ci-dessous, définissez un nom de bucket et une nouvelle clé d’objet sous un préfixe qui vous appartient :
export S3_BUCKET=your-private-bucket
export S3_KEY=php-export-test/sample.bin
Remplacez les deux valeurs d’exemple. Téléverser vers une clé existante remplace son objet actuel ou crée une nouvelle version si la gestion des versions est activée. Utilisez des clés uniques pour ces tests et exécutez un seul export à la fois.
Développer un script PHP pour exporter des fichiers
Enregistrez ce programme complet dans export.php, à côté de
composer.json. Ses arguments sont le fichier local, le bucket, la clé d’objet et un
mode facultatif, soit put, soit multipart :
<?php
declare(strict_types=1);
require __DIR__ . '/vendor/autoload.php';
use Aws\Exception\AwsException;
use Aws\Exception\MultipartUploadException;
use Aws\S3\MultipartUploader;
use Aws\S3\S3Client;
$mode = $argv[4] ?? 'put';
if ($argc < 4 || $argc > 5 || !in_array($mode, ['put', 'multipart'], true)) {
fwrite(STDERR, "Usage: php export.php LOCAL_FILE BUCKET KEY [put|multipart]\n");
exit(2);
}
[$script, $sourceFile, $bucket, $key] = $argv;
$region = getenv('AWS_DEFAULT_REGION');
if (!$region || $bucket === '' || $key === '') {
fwrite(STDERR, "Set AWS_DEFAULT_REGION and provide a nonempty bucket and key.\n");
exit(2);
}
if (!is_file($sourceFile) || !is_readable($sourceFile)) {
fwrite(STDERR, "Cannot read source file: $sourceFile\n");
exit(2);
}
try {
$s3Client = new S3Client([
'version' => '2006-03-01',
'region' => $region,
'retries' => 0,
'http' => ['connect_timeout' => 10, 'timeout' => 60],
]);
$options = [
'Bucket' => $bucket,
'Key' => $key,
'ContentType' => 'application/octet-stream',
'Metadata' => [
'original-filename' => rawurlencode(basename($sourceFile)),
'upload-date' => gmdate('c'),
],
'ServerSideEncryption' => 'AES256',
'CacheControl' => 'no-store',
];
if ($mode === 'multipart' && filesize($sourceFile) > 0) {
$uploader = new MultipartUploader($s3Client, $sourceFile, [
'bucket' => $bucket,
'key' => $key,
'part_size' => 5 * 1024 * 1024,
'concurrency' => 1,
'params' => $options,
]);
$uploader->upload();
} else {
$s3Client->putObject($options + ['SourceFile' => $sourceFile]);
}
echo "Export complete: s3://$bucket/$key\n";
} catch (Throwable $e) {
if (isset($uploader)) {
$id = $uploader->getState()->getId();
if (!empty($id['UploadId'])) {
try {
$s3Client->abortMultipartUpload($id);
fwrite(STDERR, "Aborted incomplete multipart upload.\n");
} catch (Throwable $abortError) {
fwrite(STDERR, "Abort failed; clean up upload ID: {$id['UploadId']}\n");
}
}
}
if ($e instanceof MultipartUploadException) {
fwrite(STDERR, "Multipart export failed for: $sourceFile\n");
} elseif ($e instanceof AwsException) {
fwrite(STDERR, 'S3 export failed: ' . ($e->getAwsErrorCode() ?? 'request error') . "\n");
fwrite(STDERR, 'Request ID: ' . ($e->getAwsRequestId() ?? 'unavailable') . "\n");
} else {
fwrite(STDERR, "Export failed; check the local file, SDK installation, and credentials.\n");
}
exit(1);
}
Créez un petit fichier de test et téléversez-le :
printf 'S3 export check\n' > sample.bin &&
php export.php ./sample.bin "$S3_BUCKET" "$S3_KEY"
Le script affiche Export complete, suivi de l’URI S3 de l’objet privé, uniquement après que le SDK a terminé la requête. L’URI identifie l’objet ; ce n’est pas un lien de téléchargement public. Si l’export échoue, il écrit des messages de diagnostic sur stderr et se termine avec un code de sortie non nul. Le programme lit votre fichier local sans le supprimer ; conservez ce fichier sans le modifier jusqu’à la fin de la vérification.
Gérer efficacement les métadonnées des fichiers
Le tableau $options applique les mêmes métadonnées, le même type de contenu,
la même politique de cache et le même chiffrement SSE-S3 aux deux modes de téléversement.
original-filename est encodé en pourcentage afin que les espaces et les caractères
non ASCII puissent être représentés dans un en-tête de métadonnées HTTP.
upload-date enregistre un horodatage UTC. Les clés S3 sont indépendantes des noms
de fichiers locaux ; conservez donc la clé complète pour retrouver un fichier exporté.
application/octet-stream convient aux fichiers binaires quelconques. Définissez un
ContentType plus précis lorsque votre application connaît le format et choisissez
CacheControl en fonction des applications qui utiliseront le fichier. L’exemple
utilise no-store. AES256 demande explicitement le
chiffrement SSE-S3 ;
il n’accorde pas d’accès public et ne remplace pas les contrôles d’accès.
Tester et déboguer votre intégration
Vérifiez les métadonnées stockées et le chiffrement, puis téléchargez l’objet dans un nouveau répertoire local de vérification :
aws s3api head-object --bucket "$S3_BUCKET" --key "$S3_KEY" \
--region "$AWS_DEFAULT_REGION" \
--query '{bytes:ContentLength,type:ContentType,encryption:ServerSideEncryption,metadata:Metadata}'
(
mkdir s3-verify &&
aws s3api get-object --bucket "$S3_BUCKET" --key "$S3_KEY" \
--region "$AWS_DEFAULT_REGION" s3-verify/download.bin &&
cmp -- ./sample.bin s3-verify/download.bin
)
La réponse contenant les métadonnées doit indiquer AES256, votre nom de
fichier et le nombre d’octets attendu. cmp renvoie zéro lorsque chaque
octet correspond, y compris pour un fichier vide. Utilisez un nouveau répertoire de vérification
à chaque exécution. Si un téléchargement échoue, supprimez uniquement le répertoire temporaire
s3-verify que vous avez créé, puis réexécutez le bloc. Celui-ci refuse un
répertoire existant afin de protéger les téléchargements précédents. N’utilisez pas l’ETag S3 comme
une empreinte de fichier à usage général ; les ETag des objets multipart peuvent avoir une
sémantique différente.
Testez votre propre fichier binaire non textuel et un fichier vide avec des clés distinctes avant d’intégrer le script à une tâche. Dans une tâche planifiée, capturez stderr et vérifiez le code de sortie du processus. N’incluez pas d’informations d’accès, d’URL signées ni de messages bruts d’exception du SDK dans les journaux accessibles aux utilisateurs.
Cas d’usage avancés : téléversements multipart
AWS recommande les téléversements multipart pour les objets de plus de 100 MB.
Le script vous permet également de tester ce mode avec un fichier de test plus petit : choisissez
un fichier de plus de 5 MiB pour qu’il occupe au moins deux parties, enregistrez-le dans
sample.bin et choisissez une nouvelle clé :
php export.php ./sample.bin "$S3_BUCKET" "$S3_KEY" multipart
Effectuez ensuite les mêmes vérifications des métadonnées et des octets. Pour ce fichier de test,
l’outil de téléversement utilise des parties de 5 MiB, avec une seule partie en cours de transfert,
et attend CompleteMultipartUpload avant d’afficher le message de réussite. Le SDK peut
augmenter la taille des parties pour des fichiers beaucoup plus volumineux. Les fichiers vides
utilisent putObject même lorsque vous sélectionnez le mode multipart, car ils
n’ont aucune partie à assembler.
Les nouvelles tentatives sont désactivées et chaque requête HTTP a un délai maximal de connexion de 10 secondes et un délai maximal de transfert de 60 secondes. Ces limites s’appliquent à chaque requête, et non à la durée totale du téléversement multipart. Une connexion lente peut entraîner un échec même pour un petit fichier. Cet exemple abandonne les téléversements multipart échoués au lieu de les reprendre ; corrigez le problème et relancez le script d’export avec le même fichier source local. Si l’abandon lui-même échoue, stderr indique l’identifiant du téléversement pour que l’administrateur de votre bucket puisse le supprimer. Les parties téléversées entraînent des frais de stockage jusqu’à la finalisation ou à l’abandon du téléversement, comme l’explique la présentation des téléversements multipart d’AWS.
La perte de la réponse de finalisation peut laisser le résultat incertain : S3 peut avoir validé l’objet même si le client signale un échec. Vérifiez la clé exacte et les octets avant de réessayer. Un téléversement multipart inachevé n’est pas un objet finalisé.
Bonnes pratiques de sécurité
Accordez à l’identité utilisée pour l’export s3:PutObject pour le préfixe qui lui
appartient et s3:AbortMultipartUpload pour le nettoyage en cas d’échec. L’identité utilisée
pour la vérification a également besoin de s3:GetObject pour examiner et
télécharger l’objet. Limitez ces autorisations au bucket et aux clés prévus ; le script n’a pas
besoin de l’autorisation de créer des buckets ni de modifier leurs politiques. AWS répertorie les
autorisations pertinentes dans sa
présentation des téléversements multipart.
L’exemple n’envoie aucune ACL et suppose que le bucket est privé. Il utilise explicitement SSE-S3 ; une politique de bucket qui exige SSE-KMS nécessite une modification délibérée de la configuration du chiffrement ainsi que les autorisations KMS correspondantes. Gardez la vérification des certificats TLS activée.
Résoudre les problèmes courants
- AccessDenied : Vérifiez le compte sélectionné, les autorisations du préfixe et la politique de chiffrement du bucket.
- Erreurs de région ou de point de terminaison : Faites correspondre
AWS_DEFAULT_REGIONà la région du bucket. - Fichier introuvable : Fournissez un chemin local accessible en lecture. Placez entre
guillemets les noms de fichiers contenant des espaces ; dans le shell, préfixez un nom de fichier
commençant par un trait d’union avec
./. - Échec multipart : Vérifiez dans stderr si l’abandon a échoué. Ne considérez pas un téléversement multipart restant comme un fichier stocké et vérifiez toute finalisation incertaine avant de réessayer.
- Octets différents : Vérifiez que la clé et le fichier local correspondent à ceux utilisés pour le téléversement, puis vérifiez si un autre processus d’écriture a remplacé l’objet.
Conclusion et prochaines étapes
Une fois que la comparaison après téléchargement confirme la conformité de l’objet privé, utilisez la même gestion du téléversement et du code de sortie dans votre tâche PHP. Conservez des vérifications indépendantes des octets dans vos tests d’intégration et gardez les fichiers sources locaux jusqu’à la confirmation de l’export. Pour reprendre un transfert multipart échoué, commencez par la documentation d’AWS sur la reprise avec MultipartUploader et déterminez comment votre application conservera l’état du téléversement et nettoiera les parties abandonnées.
