views:

96

answers:

9

Hi; I need to convert the following perl function to php:

pack("SSA12AC4L",
     $id,
     $loc,
     $name,
     'ar',
     split(/\./, $get->getIP),
     time+(60*60);

I use the following code (to test) in PHP:

echo pack("SSA12AC4L",
     '25',
     '00001',
     '2u7wx6fd94fd',
     'f',
     preg_split('/\./','10.2.1.1', -1, PREG_SPLIT_NO_EMPTY),
     time()+(60*60));

But I'm getting the following error: Warning: pack() [function.pack]: Type C: too few arguments in D:\wamp\www\test.php on line 8

Any suggestions? Thanks a lot.

+6  A: 

From the PHP documentation for pack().

Pack given arguments into binary string according to format.

The idea for this function was taken from Perl and all formatting codes work the same as in Perl. However, there are some formatting codes that are missing such as Perl's "u" format code.

Surely it should just work as is? You may need to rename some variables

Sbm007
+1 for the RTFM exercise :)
George Marian
@George: Might as well try to help anyways, though.
icktoofay
@icktoofay "Give a man a fish, feed him for a day..."
George Marian
@George: Or both.
icktoofay
I know, it should work but it gives me the following error: Warning: pack() [function.pack]: Type C: too few arguments in D:\wamp\www\test.php on line 8
Slim
A: 

I haven't looked at this very long, but the first thing I noticed was that you have one open paren and three closing. Is "time" supposed to be $time?

Andyourname
http://perldoc.perl.org/functions/time.html
daxim
time is not a variable
Slim
A: 

This is what I do:

echo pack("SSA12AC4L",
'25',
'00001',
'2u7wx6fd94fd',
'f',
preg_split('/\./','10.2.1.1', -1, PREG_SPLIT_NO_EMPTY),
'1278761963');

And I'm getting the following error: Warning: pack() [function.pack]: Type C: too few arguments in D:\wamp\www\test.php on line 8

Any Suggestions?

Slim
Sorry, here is the perl function that I need to convert to PHP:pack("SSA12AC4L", $id, $loc, $name, 'ar', $get->getIP, (time+60)*60);Thanks
Slim
Did you create another account? Also, you should not post this as an answer, this is not a forum. This information should be added to your question. Most people will also make a note that they've edited the question to provide more information.
George Marian
A: 

I think that the problem is that preg_split returns an array. So the array is inserted as the first char, the time as the second, and two chars are left.

I don't know how to fix this problem, but to create a temporary array:

$ip = explode('.','10.2.1.1');

And then:

echo pack("SSA12AC4L",
 '25',
 '00001',
 '2u7wx6fd94fd',
 'f',
 $ip[0],
 $ip[1],
 $ip[2]
 $ip[3],
 time()+(60*60));
nikic
Thanks for your suggestion.
Slim
A: 

The problem is that the code is giving to pack() (I am referring the the last arguments) a character, an array, and an integer. As the code C wants 4 characters, that is the cause of the error.

The code should be something like

$split = preg_split('/\./','10.2.1.1', -1, PREG_SPLIT_NO_EMPTY);
echo pack("SSA12AC4L",
  '25',
  '00001',
  '2u7wx6fd94fd',
  'f',
  $split[0],
  $split[1],
  $split[2],
  $split[3],
  time()+60*60
);

Then, there is no reason to use preg_split() in this case, when explode() can be used instead. Regular expressions should be used only when strictly necessary because the regular expression functions are slower, compared to other string functions.

kiamlaluno
Thanks, It worked fine :)
Slim
A: 

The problem is that php preg_split is converting it to an array. You need an unsigned char, so use

$x = intval(implode("", preg_split('/\./','10.2.1.1', -1, PREG_SPLIT_NO_EMPTY)));
echo pack('SSA12ACL',
     '25',
     '00001',
     '2u7wx6fd94fd',
     'f',
     $x,
     time()+(60*60));

Let know how it goes.

pinaki
and as the other posters said, you can use explode instead of preg_split if you are not expecting anything other than an IP.
pinaki
A: 

Sometimes the error statements mean something worth reviewing. Too few arguments may mean there is a need to review each input used in the PHP pack statement aligns with the expected format.

For instance, did you take into account the 'ar' field used in the perl pack statement? You might be off in the resulting packed data by one field because of that.

Steve Armstrong
A: 

My first suggestion is that you carefully read the documentation. This problem has little to do with perl and much to do with understanding what the function expects. My second suggestion is to get in the habit of feeling a little nervous whenever you copy some code. Nervous enough to pay extra attention to the code, the documentation, etc. At the very least, when a client/boss/whoever asks you what that bit of copied code does, you should have a good answer.

The first parameter to pack() is a format string. This determines how it formats the parameters when it creates the output.

From the documentation for pack():

The format string consists of format codes followed by an optional repeater argument. The repeater argument can be either an integer value or * for repeating to the end of the input data. For a, A, h, H the repeat count specifies how many characters of one data argument are taken, for @ it is the absolute position where to put the next data, for everything else the repeat count specifies how many data arguments are consumed and packed into the resulting binary string.

So, the problem is that your format string isn't appropriate for the arguments you pass to pack(). Now, keep in mind that I have to guess at the appropriate format string for your needs. You have to read the documentation and determine the correct format string.

The following works just fine:

echo pack("SSA12ACL",
'25',
'00001',
'2u7wx6fd94fd',
'f',
preg_split('/\./','10.2.1.1', -1, PREG_SPLIT_NO_EMPTY),
'1278761963');

The function preg_split() returns a single array. However, the 'C4' in the original format string expects to take in 4 parameters. Based on my count, the original format string implied 9 parameters, not 6.

George Marian
That doesn't "work just fine", it puts a complete garbage character where the IP address ought to be. How about packing `inet_pton($addr)` with `a4` or `ip2long($addr)` with `N`?
hobbs
@hobbs As I noted, I have no idea how he wants the output formatted. Also, note that the output is a **BINARY** string. "In this context, the terms binary string and byte string are used to suggest strings in which the stored data does not (necessarily) represent text." http://en.wikipedia.org/wiki/String_%28computer_science%29
George Marian
I understand that you have to guess. But guessing that the original format (from working code) is wrong and that it somehow makes sense to represent an IP address by a single byte is probably not a very *good* guess; guessing that the original format is correct and that it's meant to represent an IP address in the canonical way (4 bytes in network order) is sensible. The difficulty seems to come from the fact that perl flattens a list in a parameter list and PHP doesn't. I have no idea what your "**BINARY** string" rant is supposed to be telling us that we don't already know.
hobbs
@hobbs Fair enough, you make a good point. Regardless, it does work even if the output may be useless. Also, it's not a guess that the output format is incorrect for this code, that's a definite fact. Otherwise, pack() wouldn't be complaining. I'm a bit rusty on my perl, so I my guess couldn't be as educated as it needed to be.
George Marian
+1  A: 

It looks like you're having trouble with the fact that in Perl, if a function call is placed in the middle of a parameter list, and the called function returns a list, the items in that list are "flattened" to produce multiple arguments to the outer function; PHP doesn't do anything similar, and that's where you're getting your argument mismatch (the split should be producing four arguments to pack, but PHP only sees one -- an array value).

Fortunately the way around this is pretty easy, because there are builtin functions that will replicate what you need without any gymnastics. Try:

echo pack("SSA12ANL",
'25',
'00001',
'2u7wx6fd94fd',
'f',
ip2long('10.2.1.1'),
'1278761963');

or if that somehow fails:

echo pack("SSA12Aa4L",
'25',
'00001',
'2u7wx6fd94fd',
'f',
inet_pton('10.2.1.1'),
'1278761963');
hobbs