Скорочення URL у PHP - це один HTTP POST-запит. Надішліть довге посилання до API сервісу скорочення за допомогою розширення curl, передайте свій API-ключ як токен Bearer і зчитайте коротке посилання з відповіді через json_decode. Пакет Composer не потрібен, хоча Guzzle та HTTP-клієнт Laravel скорочують той самий запит до трьох рядків.
Більшість посібників із PHP на цю тему вже стали музейними експонатами. Вони підключають urlshortener/v1, який Google закрив після припинення створення нових посилань у 2019 році, а неактивні посилання goo.gl перестали працювати 25 серпня 2025 року, або використовують кінцеву точку bit.ly v3, що зникла багато років тому. Наведений нижче код працює з актуальним API.
Це версія для PHP загального посібника зі скорочення URL. Якщо ви ще не обрали сервіс, огляд безкоштовного API сервісу скорочення URL описує структуру запиту, модель автентифікації та ліміти, які передбачено тут. Назви полів належать Elido; структуру можна перенести.
Найшвидший спосіб: один POST-запит curl
Збережіть ключ у змінній середовища, самостійно закодуйте тіло запиту та перевірте код стану, перш ніж довіряти даним відповіді:
<?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
Два рядки тут існують через помилки, з якими кожен стикається хоча б раз. CURLOPT_RETURNTRANSFER за замовчуванням має значення false, тож без нього curl виводить JSON безпосередньо у вивід і передає вам true. Саме це насправді стоїть за більшістю запитань «моя відповідь порожня». А CURLOPT_POSTFIELDS перемикається на кодування multipart форми, щойно ви передаєте йому масив, тому саме json_encode фактично перетворює запит на JSON.
CURLINFO_RESPONSE_CODE не менш важливий. curl без жодних скарг готовий повернути тіло, що складається з {"error": "unauthorized"}.
Той самий запит у Guzzle або Laravel
Якщо в проєкті вже підключено Guzzle, шаблонний код зникає:
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 за замовчуванням створює виняток ClientException для 4xx і ServerException для 5xx. Це протилежність мовчанню curl і протилежність поведінці fetch у JavaScript. Перехоплюйте ці винятки або встановіть http_errors у false і перевіряйте стан самостійно.
У Laravel HTTP-клієнт обгортає Guzzle і безкоштовно надає повторні спроби:
$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');
retry(3, 200) означає три спроби з паузою 200 мс. Цього достатньо для короткочасного збою, але недостатньо для перевищення ліміту, про що йдеться в наступному розділі.
Скорочення посилань у WordPress
WordPress не використовує curl безпосередньо. У ньому є wp_remote_post, який сам обирає транспорт і працює на хостах, де curl вимкнено. Підключіть його до публікації, а потім збережіть результат як метадані публікації, щоб шаблони та стрічки могли його читати:
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 має зберігатися у wp-config.php, а не у файлі плагіна, який потрапить до публічного репозиторію, і не в рядку параметрів, який може прочитати кожен адміністратор. Зверніть увагу на ключ ідемпотентності: post-123 є стабільним, тож якщо хук спрацює двічі під час повторної публікації, другий виклик поверне вже наявне посилання, а не створить нове.
Якщо ви не хочете підтримувати цей хук, посібник зі скорочення URL у WordPress порівнює його з варіантами через плагін і без коду.
Хочете запустити ці фрагменти без змін? Створіть ключ на безкоштовному тарифі, експортуйте його як ELIDO_API_KEY, і наведений вище блок curl працюватиме без змін.
Повторні спроби, ліміти запитів та ідемпотентність
PHP без нагляду - завдання cron, працівник черги або імпортер масиву - має переживати 429 і короткочасну помилку 5xx. Він також має витримувати незручний випадок, коли POST-запит доходить до API, але відповідь губиться на зворотному шляху. Ваш код бачить тайм-аут, повторює запит і створює друге коротке посилання для того самого призначення, якщо ключ ідемпотентності його не зупинить.
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");
}
Коди 401 або 403 не виправляться самі, тому виняток створюється під час першої спроби, а не після трьох пауз. Код 429 очікує стільки, скільки вказує заголовок Retry-After. Лише для 5xx використовується пауза з подвоєнням. У детальному розборі лімітів запитів та ідемпотентності наведено повне обґрунтування, зокрема пояснено, чому хеш призначення зазвичай є кращим ключем, ніж випадковий UUID, коли той самий пакет можуть запускати повторно.
Є одна специфічна для PHP пастка: sleep() усередині вебзапиту утримує працівника php-fpm протягом усього часу. Повторні спроби мають належати скриптам CLI, завданням черги або WP-Cron, а не запиту, який відображає сторінку.
Масове скорочення без послідовного очікування
Цикл foreach, який скорочує 500 URL, робить 500 послідовних мережевих проходів. За 120 мс на кожен це хвилина чистого очікування. У PHP немає асинхронного середовища виконання, але є паралельні HTTP-запити, а Pool у Guzzle підтримує фіксовану кількість запитів у польоті:
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();
Ключ результатів за початковим URL зберігає видимість часткового збою та дає змогу повторно запустити процес. Без Composer ту саму роботу виконує curl_multi_init, але з більшим обсягом службового коду: додайте дескриптори, виконуйте цикл із curl_multi_exec, зберіть кожну відповідь. Почніть із паралелізму близько восьми й дозвольте заголовкам відповіді підказати, чи варто його зменшити.
Який підхід обрати
Добирайте інструмент до хоста. Спільний хостинг без Composer: звичайний блок curl. Застосунок Symfony або Laravel: Guzzle або HTTP-клієнт із повторними спробами, налаштованими один раз на рівні клієнта. WordPress: wp_remote_post у хуку публікації. Нічний імпорт тисяч посилань: пул зі стабільним ключем ідемпотентності, щоб повторний запуск був безкоштовним.
Що б ви не обрали, чотири речі залишаються незмінними: ключ надходить зі змінної середовища, для curl задано явний тайм-аут, код стану зчитується до тіла, а все, що може виконатися двічі, має ключ ідемпотентності. Команди, які переростають перший скрипт, зазвичай переходять до API та SDK або інших можливостей платформи для розробників - кліків, міток, терміну дії та вебхуків для подій посилань замість опитування.
Ознайомтеся з основною серією статей
Ця стаття належить до кластеру матеріалів для розробників. Почніть із посібника з безкоштовного API сервісу скорочення URL, щоб розібратися зі структурою кінцевої точки та автентифікацією, а потім прочитайте матеріал про ліміти запитів та ідемпотентність, щоб коректно працювати під навантаженням. Актуальна довідка - це документація API, а якщо вам дісталися посилання goo.gl, альтернатива Google URL Shortener пояснює, куди вони ведуть тепер.
Пов'язані публікації в блозі
- Як скоротити URL у JavaScript за допомогою fetch і Node
- Як скоротити URL у Python за допомогою бібліотеки requests
- Як скоротити URL у Go за допомогою net/http
- Сервіс скорочення URL для WordPress: 4 способи скоротити та відстежувати посилання
- Як скоротити URL у Ruby за допомогою Net::HTTP і Faraday
- Як скоротити URL у C# за допомогою HttpClient і .NET
Поширені запитання
Як скоротити URL у PHP?
Надішліть довгий URL до API сервісу скорочення через curl, передавши API-ключ у заголовку Bearer, а адресу призначення - у тілі JSON, потім виконайте json_decode для відповіді та зчитайте поле short_url. Це приблизно п'ятнадцять рядків із curl_setopt_array або три рядки з Guzzle чи HTTP-клієнтом Laravel, якщо один із них уже є в проєкті.
Як скоротити URL у PHP без зовнішньої бібліотеки?
Скористайтеся розширенням curl, яке постачається разом із PHP. curl_init, curl_setopt_array, curl_exec і json_decode охоплюють увесь процес без залежності від Composer, що важливо на спільному хостингу, де не можна запускати Composer. Встановіть CURLOPT_RETURNTRANSFER у true, інакше curl_exec виведе відповідь замість того, щоб її повернути.
Чи працює API Google URL Shortener у PHP?
Ні. Google припинив приймати нові посилання через API URL Shortener у 2019 році та закрив сервіс, а посилання goo.gl, які стали неактивними, перестали перенаправляти 25 серпня 2025 року. Будь-який посібник із PHP на основі urlshortener/v1 містить мертвий код, так само як і приклади bit.ly v3 тієї самої епохи.
Чи можна скоротити URL у WordPress за допомогою PHP?
Так. Викличте wp_remote_post із хука, який спрацьовує під час публікації, а потім збережіть повернуте коротке посилання за допомогою update_post_meta, щоб решта теми могла його прочитати. Зберігайте API-ключ у wp-config.php, а не у файлі плагіна чи базі даних, і перевіряйте is_wp_error для відповіді, оскільки WordPress повертає об'єкт WP_Error, а не створює виняток.
Як скоротити багато URL одночасно в PHP?
Надсилайте запити паралельно через обмежений пул, а не в циклі foreach, який очікує на кожну відповідь. Pool у Guzzle із паралелізмом приблизно вісім запитів є найкоротшим шляхом, curl_multi робить те саме без Composer, а Idempotency-Key, сформований на основі кожного URL, не дає повторному запуску створювати дублікати посилань.
Чому мій PHP-запит curl до сервісу скорочення URL повертає 401 або порожню відповідь?
Код 401 означає, що заголовок Authorization відсутній або має неправильний формат - він має точно читатися як 'Authorization: Bearer YOUR_KEY' одним рядком у масиві CURLOPT_HTTPHEADER. Порожнє повернення зазвичай означає, що CURLOPT_RETURNTRANSFER не було встановлено, тому тіло пішло безпосередньо у вивід, а curl_exec повернув true.
Спробуйте Elido
Вставте URL - отримайте коротке посилання
Без реєстрації. Посилання живе 30 днів. Зареєструйтесь, щоб зберегти назавжди.
Безкоштовно, без реєстрації · 2 на день