6 min czytaniaInżynieria

Jak skrócić URL w PHP za pomocą curl, Guzzle lub WordPressa

Skracanie URL-a w PHP za pomocą krótkiego bloku curl, tego samego wywołania w Guzzle lub Laravelu, wersji WordPressa z wp_remote_post oraz ponowień i masowego skracania.

Ana Kowalska
Marketing solutions engineering
Jak skrócić URL w PHP: żądanie POST curl wysyłające docelowy URL do API skracacza i dekodujące krótki link z odpowiedzi JSON, obok ścieżek Guzzle i WordPressa

Skrócenie URL-a w PHP to jedno żądanie HTTP POST. Wyślij długi link do API skracacza za pomocą rozszerzenia curl, przekaż klucz API jako token Bearer i wyciągnij krótki link z odpowiedzi za pomocą json_decode. Pakiet Composera nie jest wymagany, choć Guzzle i klient HTTP Laravela skracają to samo wywołanie do trzech wierszy.

Większość samouczków PHP na ten temat to eksponaty muzealne. Podłączają urlshortener/v1, które Google wycofało po zakończeniu tworzenia nowych linków w 2019 roku, przy czym nieaktywne linki goo.gl przestały działać 25 sierpnia 2025 roku, albo korzystają z endpointu bit.ly v3, który zniknął lata temu. Poniższy kod jest przeznaczony dla aktualnego API.

To wersja PHP ogólnego przewodnika po skracaniu URL-a. Jeśli nie wybrano jeszcze usługi, przegląd bezpłatnego API skracacza URL opisuje kształt żądania, model uwierzytelniania i limity przyjęte tutaj. Nazwy pól należą do Elido, ale strukturę można przenieść.

Najszybszy sposób: jedno żądanie POST curl

Umieść klucz w środowisku, zakoduj treść samodzielnie i odczytaj kod statusu, zanim zaufasz ładunkowi:

<?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

Dwa wiersze istnieją tutaj z powodu błędów, na które każdy trafia przynajmniej raz. CURLOPT_RETURNTRANSFER ma domyślnie wartość false, więc bez niego curl wypisuje JSON bezpośrednio na wyjście i przekazuje true, co jest prawdziwą przyczyną większości pytań typu "my response is empty". Z kolei CURLOPT_POSTFIELDS przełącza się na kodowanie formularza multipart, gdy przekażesz mu tablicę, dlatego właśnie json_encode tworzy prawdziwe żądanie JSON.

CURLINFO_RESPONSE_CODE jest równie ważne. curl bez problemu zwróci treść pełną {"error": "unauthorized"} i nie zgłosi żadnego problemu.

Żądanie POST PHP curl wysyłające docelowy URL i token Bearer do endpointu linków skracacza, API zwracające HTTP 201 z short_url odczytywanym przez json_decode oraz pętla ponowień zwiększająca odstępy przy odpowiedziach 429 i 5xx

To samo wywołanie w Guzzle lub Laravelu

Jeśli projekt już korzysta z Guzzle, kod pomocniczy znika:

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 domyślnie rzuca ClientException dla 4xx i ServerException dla 5xx, co jest przeciwieństwem ciszy curl i przeciwieństwem JavaScriptowego fetch. Przechwytuj je albo ustaw http_errors na false i samodzielnie sprawdzaj status.

W Laravelu klient HTTP opakowuje Guzzle i zapewnia ponowienia bez dodatkowej pracy:

$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) oznacza trzy próby z przerwą 200 ms. Wystarczy to na chwilową usterkę, ale nie na limit żądań, któremu poświęcona jest następna sekcja.

Skracanie linków wewnątrz WordPressa

WordPress nie korzysta bezpośrednio z curl. Ma wp_remote_post, które samo wybiera transport i działa na hostach, gdzie curl jest wyłączony. Podepnij je do publikacji, a następnie zapisz wynik jako metadane wpisu, aby mogły go odczytać szablony i kanały:

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 należy umieścić w wp-config.php, a nie w pliku wtyczki, który trafi do publicznego repozytorium, ani w rekordzie opcji, który może odczytać każdy administrator. Zwróć uwagę na klucz idempotencji: post-123 jest stały, więc jeśli hook uruchomi się dwa razy przy ponownej publikacji, drugie wywołanie zwróci istniejący link zamiast utworzyć kolejny.

Jeśli wolisz nie utrzymywać hooka, przewodnik po skracaczu URL dla WordPressa porównuje tę metodę z wtyczką i ścieżkami bez kodu.

Chcesz uruchomić te fragmenty dokładnie tak, jak są? Utwórz klucz w bezpłatnym planie, wyeksportuj go jako ELIDO_API_KEY, a powyższy blok curl zadziała bez zmian.

Ponowienia, limity żądań i idempotencja

Nieobsługiwany proces PHP - zadanie cron, worker kolejki, importer zbiorczy - musi przetrwać 429 i chwilowy błąd 5xx. Musi też poradzić sobie z niezręcznym przypadkiem, gdy POST dociera do API, ale odpowiedź ginie po drodze powrotnej. Kod widzi przekroczenie czasu, ponawia żądanie i tworzy drugi krótki link dla tego samego adresu, chyba że klucz idempotencji to powstrzyma.

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 lub 403 nigdy nie naprawią się same, więc kod rzuca wyjątek przy pierwszej próbie zamiast przesypiać trzy próby. 429 czeka tak długo, jak żąda tego nagłówek Retry-After. Tylko 5xx otrzymuje wykładniczo rosnący odstęp. Szczegółowe omówienie limitów żądań i idempotencji zawiera pełne uzasadnienie, w tym wyjaśnienie, dlaczego hash adresu docelowego jest zwykle lepszym kluczem niż losowy UUID, gdy tę samą partię można uruchomić ponownie.

Pułapka specyficzna dla PHP: sleep() wewnątrz żądania internetowego zajmuje workera php-fpm przez cały czas. Ponowienia powinny należeć do skryptów CLI, zadań kolejki lub WP-Cron - nie do żądania renderującego stronę.

Masowe skracanie bez sekwencyjnego oczekiwania

Pętla foreach, która skraca 500 URL-i, wykonuje 500 kolejnych podróży w obie strony. Przy 120 ms każda oznacza to minutę samego oczekiwania. PHP nie ma środowiska asynchronicznego, ale obsługuje współbieżny HTTP, a Pool Guzzle utrzymuje stałą liczbę żądań w toku:

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();
Trzy ścieżki PHP do tego samego endpointu skracacza: czysty curl na hostingu współdzielonym, Guzzle lub Laravel w aplikacji oraz wp_remote_post wewnątrz WordPressa, wszystkie odczytujące klucz API ze środowiska

Indeksowanie wyników za pomocą oryginalnego URL-a sprawia, że częściowa awaria pozostaje widoczna i można ją ponowić. Bez Composera curl_multi_init wykonuje to samo zadanie przy większej ilości kodu pomocniczego: dodaj uchwyty, wykonuj pętlę z curl_multi_exec i zbierz każdą odpowiedź. Zacznij od współbieżności około ośmiu i pozwól nagłówkom odpowiedzi pokazać, czy trzeba ją zmniejszyć.

Które podejście wybrać

Dopasuj narzędzie do hosta. Hosting współdzielony bez Composera: prosty blok curl. Aplikacja Symfony lub Laravel: Guzzle albo klient HTTP, z ponowieniami skonfigurowanymi raz na poziomie klienta. WordPress: wp_remote_post w hooku publikacji. Nocny import tysięcy linków: pula ze stałym kluczem idempotencji, dzięki któremu ponowne uruchomienie nic nie kosztuje.

Niezależnie od wyboru cztery rzeczy pozostają takie same: klucz pochodzi ze środowiska, curl otrzymuje jawny limit czasu, kod statusu jest odczytywany przed treścią, a wszystko, co może uruchomić się dwa razy, ma klucz idempotencji. Zespoły, które wychodzą poza pierwszy skrypt, zwykle chcą API i SDK albo poznać inne możliwości platformy dla deweloperów - kliknięcia, tagi, wygasanie i webhooki zdarzeń linków zamiast odpytywania.

Przeczytaj serię artykułów filarowych

Ten artykuł należy do klastra engineering. Zacznij od przewodnika po bezpłatnym API skracacza URL, aby poznać kształt endpointu i uwierzytelnianie, a następnie przeczytaj tekst o limitach żądań i idempotencji, aby poprawnie działać pod obciążeniem. Aktualnym źródłem jest dokumentacja API, a jeśli odziedziczyłeś linki goo.gl, alternatywa dla Google URL Shortener wyjaśnia, dokąd teraz prowadzą.

Powiązane artykuły na blogu

Najczęściej zadawane pytania

Jak skrócić URL w PHP?

Wyślij długi URL metodą POST do API skracacza, przekazując klucz API jako nagłówek Bearer, a adres docelowy w treści JSON, następnie użyj json_decode i odczytaj pole short_url. To około piętnastu wierszy z curl_setopt_array albo trzy wiersze z Guzzle lub klientem HTTP Laravela, jeśli projekt już go ma.

Jak skrócić URL w PHP bez zewnętrznej biblioteki?

Użyj rozszerzenia curl dołączonego do PHP. curl_init, curl_setopt_array, curl_exec i json_decode obejmują cały przepływ bez zależności od Composera, co ma znaczenie na hostingu współdzielonym, gdzie nie możesz uruchomić Composera. Ustaw CURLOPT_RETURNTRANSFER na true, bo w przeciwnym razie curl_exec wypisze odpowiedź zamiast ją zwrócić.

Czy interfejs Google URL Shortener API nadal działa w PHP?

Nie. Google przestało przyjmować nowe linki przez URL Shortener API w 2019 roku i wycofało tę usługę, a nieaktywne linki goo.gl przestały działać 25 sierpnia 2025 roku. Każdy samouczek PHP oparty na urlshortener/v1 to martwy kod, podobnie jak przykłady bit.ly v3 z tej samej epoki.

Czy mogę skrócić URL w WordPressie za pomocą PHP?

Tak. Wywołaj wp_remote_post z hooka uruchamianego podczas publikacji, a następnie zapisz zwrócony krótki link za pomocą update_post_meta, aby reszta motywu mogła go odczytać. Klucz API przechowuj w wp-config.php, a nie w pliku wtyczki ani w bazie danych, i sprawdzaj is_wp_error dla odpowiedzi, ponieważ WordPress zwraca obiekt WP_Error zamiast rzucać wyjątek.

Jak skrócić wiele URL-i naraz w PHP?

Wysyłaj żądania współbieżnie za pomocą ograniczonej puli zamiast pętli foreach, która czeka na każdą odpowiedź. Pool z Guzzle i współbieżnością około ośmiu to najkrótsza droga, curl_multi robi to samo bez Composera, a Idempotency-Key wyprowadzony z każdego URL-a sprawia, że ponowne uruchomienie nie tworzy duplikatów linków.

Dlaczego moje żądanie PHP curl do skracacza URL zwraca 401 albo pustą odpowiedź?

401 oznacza, że nagłówka Authorization brakuje albo jest zniekształcony - musi dokładnie brzmieć 'Authorization: Bearer YOUR_KEY' jako pojedynczy ciąg w tablicy CURLOPT_HTTPHEADER. Pusta wartość zwracana zwykle oznacza, że CURLOPT_RETURNTRANSFER nie został ustawiony, więc treść trafiła bezpośrednio na wyjście, a curl_exec zwrócił zamiast niej true.

Wypróbuj Elido

Wklej URL, otrzymaj krótki link

Bez rejestracji. Link działa 30 dni. Zarejestruj się, aby zachować go na zawsze.

Za darmo, bez rejestracji · 2 dziennie

Wypróbuj Elido

Skracarka URL hostowana w UE: własne domeny, głęboka analityka i otwarte API. Darmowy plan - bez karty kredytowej.

Tagi
how to shorten a url in php
php url shortener
shorten url php curl
url shortener api php
wordpress shorten url php
bulk shorten urls php

Czytaj dalej