WP_REST_Response zum Herunterladen einer Datei

Lesezeit: 5 Minuten

Ist es möglich, ein Dokument (ein generiertes PDF, eine CSV) mit dem zurückzugeben WP_REST_Response bei WordPress?

Bisher habe ich einen benutzerdefinierten Endpunkt mit registriert register_rest_resource aber wenn ich versuche, eine Datei zurückzugeben (z. B. mit PHP fpassthru($f) oder readfile($f) Ich erhalte die Fehlermeldung „Header bereits gesendet“.

Mit anderen Worten: Wie würden Sie eine Datei mit WordPress REST APIs zurückgeben?

Jede Hilfe ist willkommen!

Vielen Dank

  • “Zurückkommen zu dem? Die API gibt JSON zurück. Wenn Ihre Frage also grundsätzlich lautet: „Kann ich binäre Daten in JSON einfügen“, dann wäre die Antwort ja. Ob man das tun sollte oder unter welchen Umständen es sinnvoll sein könnte, wäre eine andere Frage.

    – CBroe

    13. Juni 2017 um 14:20 Uhr

  • Ich stimme zu, dass die API JSON an den JS-Aufgerufenen zurückgeben sollte. Aber was ist, wenn meine API (zum Beispiel) eine ID einer Bestellung als Eingabe nimmt und das PDF der Rechnung dieser Bestellung zurückgeben soll?

    – Diego Viganò

    13. Juni 2017 um 14:40 Uhr

  • Dann würde ich dies als Designfehler betrachten :p Große binäre Assets sollten überhaupt nicht über eine solche API herumgereicht werden. Ihre API sollte a zurückgeben URL für das PDF, das der Kunde dann zum Download verwenden kann.

    – CBroe

    13. Juni 2017 um 14:42 Uhr

  • Ja, aber dies würde zwei Aufrufe erfordern: den ersten, um die PDF-Datei zu generieren und auf der Serverfestplatte zu speichern, und einen zweiten, um die auf der Festplatte gespeicherte PDF-Datei tatsächlich herunterzuladen.

    – Diego Viganò

    13. Juni 2017 um 16:18 Uhr

  • URLs müssen nicht auf „statische“ Daten oder Dateien verweisen.

    – CBroe

    13. Juni 2017 um 16:49 Uhr

Standardmäßig werden alle REST-Antworten durchgeleitet json_encode() um einen JSON-String zurückzugeben. Der REST-Server stellt jedoch den WP-Hook bereit rest_pre_serve_request die wir verwenden können, um stattdessen binäre Daten zurückzugeben.

Codebeispiel:

<?php
/**
 * Serves an image via the REST endpoint.
 *
 * By default, every REST response is passed through json_encode(), as the
 * typical REST response contains JSON data.
 *
 * This method hooks into the REST server to return a binary image.
 *
 * @param string $path Absolute path to the image to serve.
 * @param string $type The image mime type [png|jpg|gif]. Default is 'png'.
 *
 * @return WP_REST_Response The REST response object to serve an image.
 */
function my_serve_image( $path, $type="png" ) {
    $response = new WP_REST_Response;

    if ( file_exists( $path ) ) {
        // Image exists, prepare a binary-data response.
        $response->set_data( file_get_contents( $path ) );
        $response->set_headers( [
            'Content-Type'   => "image/$type",
            'Content-Length' => filesize( $path ),
        ] );

        // HERE → This filter will return our binary image!
        add_filter( 'rest_pre_serve_request', 'my_do_serve_image', 0, 2 );
    } else {
        // Return a simple "not-found" JSON response.
        $response->set_data( 'not-found' );
        $response->set_status( 404 );
    }

    return $response;
}

/**
 * Action handler that is used by `serve_image()` to serve a binary image
 * instead of a JSON string.
 *
 * @return bool Returns true, if the image was served; this will skip the
 *              default REST response logic.
 */
function my_do_serve_image( $served, $result ) {
    $is_image   = false;
    $image_data = null;

    // Check the "Content-Type" header to confirm that we really want to return
    // binary image data.
    foreach ( $result->get_headers() as $header => $value ) {
        if ( 'content-type' === strtolower( $header ) ) {
            $is_image   = 0 === strpos( $value, 'image/' );
            $image_data = $result->get_data();
            break;
        }
    }

    // Output the binary data and tell the REST server to not send any other
    // details (via "return true").
    if ( $is_image && is_string( $image_data ) ) {
        echo $image_data;

        return true;
    }

    return $served;
}

Beispielverwendung:

<?php
// Register the REST endpoint.
register_rest_route( 'my_sample/v1', 'image', [
    'method' => 'GET',
    'callback' => 'my_rest_get_image'
] );

// Return the image data using our function above.
function my_rest_get_image() {
    return my_serve_image( 'path/to/image.jpeg', 'jpg' );
}

  • Wenn Sie versuchen, die Anführungszeichen um eine Zeichenfolge für eine Datei zu entfernen, z. B. für eine CSV-Datei, können Sie diese Technik auch verwenden (diesen Kommentar nur hinzufügen, weil mein ursprünglicher Suchausdruck „Anführungszeichen aus WP_REST_Response entfernen“ war und es eine Weile gedauert hat, bis ich das bekommen habe hier. Hoffentlich wird dieser Kommentar indiziert und führt die Leute hierher)

    – TheCrzyMan

    31. August um 23:52 Uhr

(Ich brauche das bald selbst, um eine Antwort zu formulieren, die vielleicht unvollständig ist.)

Nach Rücksprache mit WP Media kommen wir weiter .../?rest_route=/wp/v2/media/ID a JSON API Antwort mit Links für die angeforderten Mediendateien.

Entlang dh für Bild eines der folgen source _url enthält .../wp-content/uploads/2021/06/Screenshot-2021-06-18-at-10.25.05-150x150.png.

Folgen Sie den Kommentaren (nicht binär streamen, sondern verknüpfen), fügen Sie die Datei zur WP Media-Sammlung hinzu, oder der benutzerdefinierte Endpunkt könnte mit einer ähnlichen Antwort antworten, die mit der generierten UND gespeicherten Datei verknüpft ist.

Dann kann jeder JSON-API-kompatible Client das tun, was erforderlich ist. Generieren Sie in diesem Fall einen Download-Link.

Sie können nicht verwenden WP_REST_Response um dies zu tun. Es ist jedoch möglich, etwas anderes mit der Rest-API zurückzugeben.

Wenn Sie absolut sicher sind, dass Sie die haben Komplett antwortbereit (einschließlich Header, wie z Content-Disposition für Downloads), können Sie einfach exit; nach dem Generieren der endgültigen Antwort. Beachten Sie, dass dies alle Hooks, die danach aufgerufen worden wären, vollständig umgeht, also verwenden Sie es mit Vorsicht.

Ein Beispiel mit .csv

$filename="example-file.csv";
header("Access-Control-Expose-Headers: Content-Disposition", false);
header('Content-type: text/csv');
header("Content-Disposition: attachment; filename=\"$filename\"");

// output starts here, do not add headers from this point on.
$csv_file = fopen('php://output', 'w');

$csv_header = array(
    'column-1',
    'column-2',
    'column-3',
);

fputcsv($csv_file, $csv_header);

$data = array(
    array('a1', 'b1', 'c1'),
    array('a2', 'b2', 'c2'),
    array('a3', 'b3', 'c3'),
);

foreach ($data as $csv_data_entry) {
    fputcsv($csv_file, $csv_data_entry);
}

fclose($csv_file);

// With a non-file request, you would usually return the result.
// In this case, this would cause the "Headers already sent" errors, so an exit is required.
exit;

1393180cookie-checkWP_REST_Response zum Herunterladen einer Datei

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy