0

There is a service (php) which sends an image to a client (php).

header('Content-Type: image/png');
readfile($image);

What if it is needed to send not only an image but some data with it.

$arrayToSend = [
    'image' => file_get_contents($image),
    'some_data' => [
        'a' => 1,
        'b' => 2
    ]
];

How the service can pack $arrayToSend so that the client can unpack it?

Without converting image to base64 (because of too large size).

2 Answers 2

1

@Danon's header approach is probably the way to go if you're communicating over HTTP, but other transports may not support sending additional headers, so you would need to pack them in with the binary data, then unpack on the receiving side.

<?php
class Codec
{
    /**
     * Pack metadata along with binary data
     *
     * @param $meta
     * @param $data
     * @return false|string
     */
    public static function encode($meta, $data)
    {
        $meta = base64_encode($meta);

        //determine length of metadata
        $metaLength = strlen($meta);

        //The first part of the message is the metadata length
        $output = pack('VA*', $metaLength, $meta);

        //Length and metadata are set, now include the binary data
        $output .= $data;

        return $output;
    }

    /**
     * Unpack data encoded via the encode function.
     * Returns an array with "meta" and "data" elaments
     *
     * @param $content
     * @return array
     */
    public static function decode($content)
    {
        //Get the length of the metadata content
        $metaLength = unpack('V', $content)[1];

        //Slice out the metatdata, offset 4 to account for the length bytes
        $metaPacked = substr($content, 4, $metaLength);

        //Unpack and base64 decode the metadata
        $meta = unpack('A*', $metaPacked)[1];
        $meta = base64_decode($meta);

        //The binary data is everything after the metadata
        $data = substr($content, $metaLength+4);

        return [
            'meta' => $meta,
            'data' => $data
        ];
    }
}

//Load contents of a binary file
$imageFilePath = 'path_to_image.png';
$data = file_get_contents($imageFilePath);

//Arbitrary metadata - could be anything, let's use JSON
$meta = [
    'filename' => 'foo.png',
    'uid' => 12345,
    'md5' => md5_file($imageFilePath)
];

$metaJson = json_encode($meta);

//Encode the message, you can then send this to the receiver
$payload = Codec::encode($metaJson, $data);

//Receiver decodes the message
$result = Codec::decode($payload);

//Decode our JSON string
$resultMeta = json_decode($result['meta'], true);


echo 'Filename: '.$resultMeta['filename'].PHP_EOL;
echo 'UID: '.$resultMeta['uid'].PHP_EOL;

//We included an MD5 hash of the file, so we can verify here
if($resultMeta['md5'] != md5($result['data']))
{
    echo 'MD5 mismatch!';
}
Sign up to request clarification or add additional context in comments.

3 Comments

I'd actually go for the Non-HTTP way, but you're using base64_encode(), which the asker specifically asked not to include :/ Maybe there's another non-http way without re-encoding data?
They said they didn’t want to base64 the binary, I’m only encoding the added meta data.
Rob's answer is the right answer to the asked question, but I will use Danon's solution (send a header) because it suits me enough. Thank you both. Both answers are very helpful.
1

Maybe you could pass some_data-a and some_data-b as headers? For example, as a cookie.

You can help yourself with this document: https://developer.mozilla.org/pl/docs/Web/HTTP/Headers for more information about headers.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.