Raccourcir une URL en PHP se résume à un POST HTTP. Envoyez le lien long à l'API d'un service de raccourcissement avec l'extension curl, transmettez votre clé API comme jeton Bearer, puis extrayez le lien court de la réponse avec json_decode. Aucun paquet Composer n'est nécessaire, même si Guzzle et le client HTTP Laravel réduisent le même appel à trois lignes.
La plupart des tutoriels PHP sur le sujet sont des pièces de musée. Ils configurent urlshortener/v1, que Google a retiré après avoir mis fin à la création de nouveaux liens en 2019, avec les liens goo.gl inactifs qui ont cessé de fonctionner le 25 août 2025, ou utilisent le point de terminaison bit.ly v3 disparu depuis des années. Le code ci-dessous cible une API actuelle.
Voici la version PHP du guide général pour raccourcir une URL. Si vous n'avez pas encore choisi de service, la présentation de l'API gratuite de raccourcissement d'URL couvre la forme des requêtes, le modèle d'authentification et les limites supposées ici. Les noms de champs sont ceux d'Elido ; la structure se transpose.
La méthode la plus rapide : un POST curl
Placez la clé dans l'environnement, encodez vous-même le corps et lisez le code d'état avant de faire confiance à la charge utile :
<?php
$ch = curl_init('https://api.elido.app/v1/links');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 10,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer ' . getenv('ELIDO_API_KEY'),
'Content-Type: application/json',
],
CURLOPT_POSTFIELDS => json_encode([
'destination_url' => 'https://example.com/spring-sale?utm_source=newsletter',
]),
]);
$body = curl_exec($ch);
$status = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
curl_close($ch);
if ($body === false || $status >= 400) {
throw new RuntimeException("shorten failed: HTTP {$status}");
}
$link = json_decode($body, true, 512, JSON_THROW_ON_ERROR);
echo $link['short_url']; // https://s.elido.me/ab12cd
Deux lignes sont là à cause de bugs que tout le monde rencontre au moins une fois. CURLOPT_RETURNTRANSFER vaut false par défaut : sans cette option, curl affiche le JSON directement et vous renvoie true, ce qui explique la plupart des questions du type "ma réponse est vide". Et CURLOPT_POSTFIELDS passe à l'encodage de formulaire multipart dès que vous lui transmettez un tableau ; c'est donc json_encode qui transforme réellement la requête en requête JSON.
CURLINFO_RESPONSE_CODE est tout aussi important. curl accepte volontiers de renvoyer un corps rempli de {"error": "unauthorized"} sans se plaindre le moins du monde.
Le même appel avec Guzzle ou Laravel
Si le projet utilise déjà Guzzle, le code répétitif disparaît :
use GuzzleHttp\Client;
$client = new Client([
'base_uri' => 'https://api.elido.app',
'timeout' => 10,
'headers' => ['Authorization' => 'Bearer ' . getenv('ELIDO_API_KEY')],
]);
$response = $client->post('/v1/links', [
'json' => ['destination_url' => $destination],
'headers' => ['Idempotency-Key' => hash('sha256', $destination)],
]);
$short = json_decode((string) $response->getBody(), true)['short_url'];
Guzzle lève par défaut une ClientException pour les 4xx et une ServerException pour les 5xx, ce qui est l'inverse du silence de curl et l'inverse du comportement de fetch en JavaScript. Interceptez-les, ou définissez http_errors sur false et vérifiez vous-même le statut.
Dans Laravel, le client HTTP enveloppe Guzzle et vous fournit gratuitement les nouvelles tentatives :
$short = Http::withToken(config('services.elido.key'))
->timeout(10)
->retry(3, 200, throw: false)
->post('https://api.elido.app/v1/links', ['destination_url' => $destination])
->json('short_url');
Ce retry(3, 200) correspond à trois tentatives avec une pause de 200 ms. C'est suffisant pour une perturbation passagère, mais pas pour une limitation de débit, qui fait l'objet de la section suivante.
Raccourcir des liens dans WordPress
WordPress n'utilise pas directement curl. Il dispose de wp_remote_post, qui choisit un transport à votre place et fonctionne sur les hébergeurs où curl est désactivé. Déclenchez-le à la publication, puis stockez le résultat dans les métadonnées de l'article pour que les modèles et les flux puissent le lire :
add_action('publish_post', function (int $post_id): void {
if (get_post_meta($post_id, '_elido_short_url', true)) {
return; // already shortened
}
$response = wp_remote_post('https://api.elido.app/v1/links', [
'timeout' => 10,
'headers' => [
'Authorization' => 'Bearer ' . ELIDO_API_KEY,
'Content-Type' => 'application/json',
'Idempotency-Key' => 'post-' . $post_id,
],
'body' => wp_json_encode(['destination_url' => get_permalink($post_id)]),
]);
if (is_wp_error($response)) {
error_log('shorten failed: ' . $response->get_error_message());
return;
}
$link = json_decode(wp_remote_retrieve_body($response), true);
update_post_meta($post_id, '_elido_short_url', $link['short_url']);
}, 10, 1);
ELIDO_API_KEY doit se trouver dans wp-config.php, pas dans un fichier d'extension qui finirait dans un dépôt public ni dans une ligne d'options que tous les administrateurs peuvent lire. Remarquez la clé d'idempotence : post-123 est stable ; si le hook se déclenche deux fois lors d'une nouvelle publication, le second appel renvoie le lien déjà existant au lieu d'en créer un deuxième.
Si vous préférez ne pas gérer ce hook, le guide du raccourcisseur WordPress compare cette méthode avec les solutions par extension et sans code.
Vous voulez exécuter ces extraits tels quels ? Créez une clé avec l'offre gratuite, exportez-la sous le nom ELIDO_API_KEY, et le bloc curl ci-dessus fonctionnera sans modification.
Nouvelles tentatives, limitations de débit et idempotence
Un PHP sans supervision - tâche cron, worker de file d'attente ou importateur en masse - doit survivre à un 429 et à un 5xx passager. Il doit aussi gérer le cas délicat où le POST atteint l'API mais où la réponse se perd sur le chemin du retour. Votre code constate un délai d'attente, effectue une nouvelle tentative et crée un deuxième lien court pour la même destination, sauf si une clé d'idempotence l'en empêche.
function shorten(string $destination, int $retries = 3): string
{
$key = hash('sha256', $destination); // stable across retries and re-runs
for ($attempt = 0; $attempt < $retries; $attempt++) {
[$body, $status, $retryAfter] = post_link($destination, $key);
if ($status === 429) {
sleep(max(1, (int) $retryAfter));
continue;
}
if ($status >= 500) {
sleep(2 ** $attempt); // exponential backoff
continue;
}
if ($status >= 400) {
throw new RuntimeException("shorten failed: HTTP {$status} {$body}");
}
return json_decode($body, true, 512, JSON_THROW_ON_ERROR)['short_url'];
}
throw new RuntimeException("shorten failed after {$retries} attempts");
}
Un 401 ou un 403 ne se réparera jamais seul : le code lève donc une exception dès la première tentative au lieu d'attendre trois fois. Un 429 attend le délai demandé par l'en-tête Retry-After. Seuls les 5xx bénéficient du délai croissant. L'analyse approfondie des limitations de débit et de l'idempotence explique tout le raisonnement, notamment pourquoi le hachage de la destination constitue généralement une meilleure clé qu'un UUID aléatoire lorsque le même lot peut être exécuté à nouveau.
Un piège propre à PHP : sleep() dans une requête web monopolise un worker php-fpm pendant toute sa durée. Les nouvelles tentatives ont leur place dans des scripts CLI, des jobs de file d'attente ou WP-Cron, pas dans la requête qui génère une page.
Raccourcissement en masse sans attente séquentielle
Une boucle foreach qui raccourcit 500 URL effectue 500 allers-retours successifs. À 120 ms chacun, cela représente une minute d'attente pure. PHP n'a pas de moteur asynchrone, mais il sait effectuer des requêtes HTTP simultanées, et le Pool de Guzzle maintient un nombre fixe de requêtes en cours :
use GuzzleHttp\Pool;
use GuzzleHttp\Psr7\Request;
$requests = static function (array $urls) {
foreach ($urls as $url) {
yield new Request('POST', '/v1/links', [
'Content-Type' => 'application/json',
'Idempotency-Key' => hash('sha256', $url),
], json_encode(['destination_url' => $url]));
}
};
$short = [];
$pool = new Pool($client, $requests($urls), [
'concurrency' => 8,
'fulfilled' => function ($response, $i) use (&$short, $urls) {
$short[$urls[$i]] = json_decode((string) $response->getBody(), true)['short_url'];
},
'rejected' => function ($reason, $i) use (&$short, $urls) {
$short[$urls[$i]] = 'ERROR: ' . $reason->getMessage();
},
]);
$pool->promise()->wait();
Associer les résultats à l'URL d'origine laisse visible un échec partiel et permet de relancer l'opération. Sans Composer, curl_multi_init fait le même travail avec davantage de gestion : ajoutez les handles, bouclez sur curl_multi_exec et récupérez chaque réponse. Commencez avec une simultanéité d'environ huit et laissez les en-têtes de réponse vous indiquer s'il faut la réduire.
Quelle méthode choisir ?
Adaptez l'outil à l'hébergement. Hébergement mutualisé sans Composer : le bloc curl simple. Application Symfony ou Laravel : Guzzle ou le client HTTP, avec les nouvelles tentatives configurées une fois au niveau du client. WordPress : wp_remote_post sur un hook de publication. Import nocturne de milliers de liens : le pool, avec une clé d'idempotence stable pour qu'une nouvelle exécution ne coûte rien.
Quelle que soit votre méthode, quatre éléments restent identiques : la clé vient de l'environnement, curl reçoit un délai d'attente explicite, le code d'état est lu avant le corps, et tout ce qui peut s'exécuter deux fois porte une clé d'idempotence. Les équipes qui dépassent le premier script veulent généralement l'API et les SDK ou ce que la plateforme met d'autre à la disposition des développeurs : clics, tags, expiration, webhooks pour les événements de lien plutôt que de l'interrogation périodique.
Lire la série de référence
Cet article appartient au cluster engineering. Commencez par le guide de l'API gratuite de raccourcissement d'URL pour la structure du point de terminaison et l'authentification, puis consultez l'article sur les limitations de débit et l'idempotence pour vous comporter correctement sous charge. La référence à jour se trouve dans la documentation de l'API, et si vous avez hérité de liens goo.gl, l'alternative à Google URL Shortener explique ce qu'ils deviennent désormais.
À lire sur le blog
- Comment raccourcir une URL en JavaScript avec fetch et Node
- Comment raccourcir une URL en Python avec la bibliothèque requests
- Comment raccourcir une URL en Go avec net/http
- Raccourcisseur d'URL WordPress : 4 façons de raccourcir et suivre les liens
- Comment raccourcir une URL en Ruby avec Net::HTTP et Faraday
- Comment raccourcir une URL en C# avec HttpClient et .NET
Questions fréquentes
Comment raccourcir une URL en PHP ?
Envoyez l'URL longue à l'API d'un service de raccourcissement avec curl, en transmettant votre clé API dans un en-tête Bearer et la destination dans un corps JSON, puis appliquez json_decode à la réponse et lisez le champ short_url. Il faut environ quinze lignes avec curl_setopt_array, ou trois avec Guzzle ou le client HTTP Laravel si le projet en utilise déjà un.
Comment raccourcir une URL en PHP sans bibliothèque externe ?
Utilisez l'extension curl fournie avec PHP. curl_init, curl_setopt_array, curl_exec et json_decode couvrent tout le flux sans dépendance Composer, ce qui compte sur un hébergement mutualisé où vous ne pouvez pas exécuter Composer. Définissez CURLOPT_RETURNTRANSFER sur true, sinon curl_exec affiche la réponse au lieu de la renvoyer.
L'API Google URL Shortener fonctionne-t-elle encore en PHP ?
Non. Google a cessé d'accepter de nouveaux liens via l'API URL Shortener en 2019 et a retiré le service ; les liens goo.gl devenus inactifs ont cessé de rediriger le 25 août 2025. Tout tutoriel PHP fondé sur urlshortener/v1 est du code obsolète, et les exemples bit.ly v3 de la même époque ont eux aussi disparu.
Puis-je raccourcir une URL dans WordPress avec PHP ?
Oui. Appelez wp_remote_post depuis un hook déclenché lors de la publication, puis stockez le lien court renvoyé avec update_post_meta afin que le reste du thème puisse le lire. Gardez la clé API dans wp-config.php plutôt que dans un fichier d'extension ou la base de données, et vérifiez is_wp_error sur la réponse, car WordPress renvoie un objet WP_Error au lieu de lever une exception.
Comment raccourcir beaucoup d'URL en une seule fois en PHP ?
Envoyez les requêtes simultanément avec un pool borné plutôt qu'avec une boucle foreach qui attend chaque réponse. Le Pool de Guzzle avec une simultanéité d'environ huit est la solution la plus courte ; curl_multi fait la même chose sans Composer, et une Idempotency-Key dérivée de chaque URL empêche une nouvelle exécution de créer des liens en double.
Pourquoi ma requête PHP curl vers un raccourcisseur d'URL renvoie-t-elle 401 ou une réponse vide ?
Un 401 signifie que l'en-tête Authorization est absent ou mal formé : il doit être exactement 'Authorization: Bearer YOUR_KEY' sous la forme d'une seule chaîne dans le tableau CURLOPT_HTTPHEADER. Une valeur de retour vide signifie généralement que CURLOPT_RETURNTRANSFER n'a jamais été défini : le corps est donc parti directement vers la sortie et curl_exec a renvoyé true.
Essayer Elido
Collez une URL, obtenez un lien court
Sans inscription. Lien actif 30 jours. Inscrivez-vous pour le garder pour toujours.
Gratuit, sans inscription · 2 par jour