PHP Passing an array to pack () function

pack()

syntax (from http://php.net/manual/en/function.pack.php )

string pack ( string $format [, mixed $args [, mixed $... ]] )

so, assuming that I need to pack three bytes

$packed = pack( "c*", 65, 66, 67 );

But what if I need to pack an arbitrary number of bytes?

They could be conveniently stored in an array so that I would naively try

$a = array( 65, 66, 67 );
$packed = pack( "c*", $a );

      

But that won't work.

Is there a way to make the pack()

array work?

+3


source to share


5 answers


A bit late to the party, but for future reference, you can use the new operator ...

(v5.6 +) to blow up the inline array:



$packed = pack("c*", ...$a);

      

+7


source


You can create your own function array_pack

that calls internally pack

using call_user_func or call_user_func_array so that you can pass the correct number of parameters to it.

Maybe something like this might work (not tested though ... But you get the general idea)



function array_pack(array $arr) {
  return call_user_func_array("pack", array_merge(array("c*"), $arr));
}

      

+2


source


use string concatenation instead pack()

When packing bytes, packed binary data (string) can be obtained by simple use chr()

, concatenation .

and loop foreach

:

packed = "";
foreach ( $a as $byte ) {
    $packed .= chr( $byte );
}

      

Where $a

is the original array and $packed

is the resulting binary data stored in a string variable as per the original question.


test

Having come, at the time of writing, with 5 different working solutions , it is worth doing a test if the amount of data in the package is huge.

I checked five cases with 1048576 array of elements to get 1MB of binary data. I measured the runtime and memory consumed.

Test conditions: PHP 5.6.30

- Mac OS X

-2.2 GHz Intel Core I7

(of course only one core is used)

// pack with ... operator:    57 ms - 1.3 MB
// string concatentation:    197 ms - 1.3 MB
// call_user_func_array:     249 ms - 1.5 MB
// multiple pack:            298 ms - 1.3 MB
// array_reduce:           39114 ms - 1.3 MB

      

Operator ...

used directly with a function pack

, if actually the fastest solution ( accepted answer )

If ...

not available (PHP version prior to 5.6), the solution suggested by this answer ( ) is the fastest. string concatentation

Memory usage is almost the same for every case.

I am posting the test code if anyone is interested.


<?php

// Return elapsed time from epoch time in milliseconds

function milliseconds() {
    $mt = explode(' ', microtime());
    return ((int)$mt[1]) * 1000 + ((int)round($mt[0] * 1000));
}



// Which test to run [1..5]

$test = $argv[ 1 ];



// Test 1024x1024 sized array

$arr = array();
for( $i = 0; $i < 1024 * 1024; $i++ )
{
    $arr[] = rand( 0, 255 );
}



// Initial memory usage and time

$ms0 = milliseconds();
$mem0 = memory_get_usage( true );



// Test 1: string concatentation

if( $test == '1' )
{
    $data = "";
    foreach ( $arr as $byte ) {
        $data .= chr( $byte );
    }

    $test = "string concatentation";
}



// Test 2: call_user_func_array

if( $test == '2' )
{
    $data = call_user_func_array("pack", array_merge(array("c*"), $arr));

    $test = "call_user_func_array";
}



// Test 3: pack with ... operator

if( $test == '3' )
{
    $data = pack("c*", ...$arr);

    $test = "pack with ... operator";
}



// Test 4: array_reduce

if( $test == '4' )
{
    $data = array_reduce($arr, function($carry, $item) { return $carry .= pack('c', $item); });

    $test = "array_reduce";
}



// Test 5: Multiple pack

if( $test == '5' )
{
    $data = "";
    foreach ($arr as $item) $data .= pack("c", $item);

    $test = "multiple pack";
}



// Output result

$ms = milliseconds() - $ms0;
$mem = round( ( memory_get_usage( true ) - $mem0 ) / ( 1024 * 1024 ), 1 );
echo "$test: $ms ms; $mem MB\n";

      

+2


source


I am using this function:

private function pack_array($format, $arg)
{
    $result="";
    foreach ($arg as $item) $result .= pack ($format, $item);
    return $result;
}

      

+1


source


Another option if you cannot use the operator ...

:

$packed = array_reduce($a, function($carry, $item) {
    return $carry .= pack('c', $item);
});

      

0


source







All Articles