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.
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
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.
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');
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.
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));
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.
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.
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?
Related
I have a php file with thread ($tid) and post ($pid) ids defined and I'm looking to use str_replace to combine them and create my desired output (below) with &p= added:
Desired output:
$tid&p=$pid
The closest I've got is doing this:
$tid=$t1;
$pid=$p1;
$tid=str_replace("$tid","$tid"."$pid",$tid);
The result is:
$tid$pid
I may need to use a function (not sure which if so?) in the str_replace to support the &p= being added, as trying to add it in the quotes directly doesn't seem to work resulting only in database errors.
Edit #1: I tried doing the following based on the comments thus far:
$tid="";
$tid.="$t1";
$tid.="$p1";
$tid=$tid;
That results in the same as my previous example above:
$tid$pid
As soon as I add another with the &p= I get a database error:
$tid.="&p=";
So my question now is how to add the &p= to my Edit #1 example above correctly?
I'm attempting to understand the question a little bit. You have a couple options that are alluded to in the comments above. You could, for instance (where '1', '2', and '3' are replaced by the desired values):
<?php
$tid=1;
$pid=2;
$amp=3;
$tid=str_replace("$tid","$tid".'$amp;p='."$pid",$tid);
echo $tid;
?>
Here you can just explicitly state in the 'replace' argument of str_replace that the missing string should be part of the replacement string.
or you could also simply use the a concatenation operator to generate the string you desire which is probably simpler given what (little) I know of the surrounding code/use-case:
<?php
$tid=1;
$pid=2;
$amp=3;
echo "$tid".'$amp;p='."$pid";
?>
The reason I'd recommend the latter, is due to the fact that it's less resource intensive to actually produce the desired result which appears to just be a string. str_replace() searches the "haystack" or subject string using the search string and then must replace each of the found instances with the replace string.
i'm using $_POSTto send form values to PHP and then insert into database, i have some inputs for prices values that looks like this:
1.000.000,00 (1 million in BRL "Brazilian Real")
I need to convert it to 1000000.00 (DECIMAL(10,2) to insert into database)
How can i do that using PHP number_format()?
Thanks!
EDIT
If number_format() is not the function i'm looking for, what's best to be using in this case?
Also, i need help finding a solution, even if the user value is 100.000,00
You can not do that with number format, it works other way around.
The thing that you do is bad practice, View layer should send primitive data to Controller - if you are using some advanced javascript component to represent to the user formatted number, that is fine, but underlaying form control should send primitive data, i.e. 10000000.00
Now, if nothing that I have stated to you is not applicable at this particular moment, and having in mind that this format that you have send is fixed (dot for thousand separator, coma for decimal separator), you can clean the value by using simple str_replace.
But, the trick is to replace first dot with empty string, then coma with dot.
str_replace(',', '.',str_replace('.', '', $number));
Got it?
But know that what you are doing is bad approach and wrong implementation, eventually, it will bite you in the a**.
<?php
$number = '1.000.000,00';
$replaced_number = str_replace(array('.',','), array('',''), $number);
echo number_format($replaced_number,2,'.','');
?>
The easiest way is to use str_replace() function:
<?php
$p = '1.000.000,00';
$p = str_replace('.', '', $p);
$p = str_replace(',', '.', $p);
echo $p;
At first replace the (.) and (,) with str_replace by '' and then use t the following function
number_format($replaced_number,$decimal)
If you have a look at php.net you will easily see the right syntax for your goal:
number_format($number,2,'.','')
The first parameter is the number of decimal places that in your case is 2.
The second is the symbol to use for decimal separator and the third is the one to be used for thousands that in your case will be nothing .
Ok, am trying to find a character or group of characters, or something that can be used that I can explode from, since the text is user-defined, I need to be able to explode from a value that I have that can never be within the text.
How can I do this?
An example of what I'm trying to do...
$value = 'text|0||#fd9||right';
Ok,
text is something that should never change in here.
0, again not changeable
#fd9 is a user-defined string that can be anything that the user inputs...
and right sets the orientation (either left or right).
So, the problem I'm facing is this: How to explode("||", $value) so that if there is a || within the user-defined part... Example:
$value = 'text|0||Just some || text in here||right';
So, if the user places the || in the user-defined part of the string, than this messes this up. How to do this no matter what the user inputs into the string? So that it should return the following array:
array('text|0', 'Just some || text in here', 'right');
Should I be using different character(s) to explode from? If so, what can I use that the user will not be able to input into the string, or how can I check for this, and fix it? I probably shouldn't be using || in this case, but what can I use to fix this?
Also, the value will be coming from a string at first, and than from the database afterwards (once saved).
Any Ideas?
The problem of how to represent arbitrary data types as strings always runs up against exactly the problem you're describing and it has been solved in many ways already. This process is called serialization and there are many serialization formats, anything from PHP's native serialize to JSON to XML. All these formats specify how to present complex data structures as strings, including escaping rules for how to use characters that have a special meaning in the serialization format in the serialized values themselves.
From the comments:
Ok, well, basically, it's straight forward. I already outlined 13 of the other parameters and how they work in Dream Portal located here: http://dream-portal.net/topic_122.0.html so, you can see how they fit in. I'm working on a fieldset parameter that basically uses all of these parameters and than some to include multiple parameters into 1. Anyways, hope that link helps you, for an idea of what an XML file looks like for a module: http://dream-portal.net/topic_98.0.html look at the info.xml section, pay attention to the <param> tag in there, at the bottom, 2 of them.
It seems to me that a more sensible use of XML would make this a lot easier. I haven't read the whole thing in detail, but an XML element like
<param name="test_param" type="select">0:opt1;opt2;opt3</param>
would make much more sense written as
<select name="test_param">
<option default>opt1</option>
<option>opt2</option>
<option>opt3</option>
</select>
Each unique configuration option can have its own unique element namespace with custom sub-elements depending on the type of parameter you need to represent. Then there's no need to invent a custom mini-format for each possible parameter. It also allows you to create a formal XML schema (whether this will do you any good or not is a different topic, but at least you're using XML as it was meant to be used).
You can encode any user input to base64 and then use it with explode or however you wish.
print base64_encode("abcdefghijklmnopqrstuvwxyz1234567890`~!##$%^&*()_+-=[];,./?>:}{<");
serialized arrays are also not a bad idea at all. it's probably better than using a comma separated string and explode. Drupal makes good use of serialized arrays.
take a look at the PHP manual on how to use it:
serialize()
unserialize()
EDIT: New Solution
Is it a guarantee that text doesn't contain || itself?
If it doesn't, you can use substr() in combination with strpos() and strrpos() instead of explode
Here's what I usually do to get around this problem.
1) capture user's text and save it in a var $user_text;
2) run an str_replace() on $user_text to replace the characters you want to split by:
//replace with some random string the user would hopefully never enter
$modified = str_replace('||','{%^#',$user_text);
3) now you can safely explode your text using ||
4) now run an str_replace on each part of the explode, to set it back to the original user entered text
foreach($parts as &$part) {
$part = str_replace('{%^#','||',$part);
}
Basically, I have a directory with a bunch of files names that I have loaded into an array. The file names tell me something about the text they represent (i.e. Prologue, chapterone, chaptertwo), but in the file name I also include a sequential number to keep them ordered. So 'prollecture1.xml', 'prollecture2.xml', 'prollecture3.xml', . . . 'prollecture12.xml', 'chapteronelecture13.xml', 'chapteronelecture14.xml'. . . 'conclusionlecture18.xml', etc.
I want to sort this so that the array lists them in numerical order. Using a "natural comparison sort" gets me close, but the sort begins with the first character of the file name, and thus 'chapteronelecture13.xml' is listed before 'prollecture1.xml' because 'c' comes before 'p'. If had known I wanted to do this from the beginning I would have put the numbers first. But to change all the file names now would be a lot of work.
My question: is there a way to the get the "natural string comparison" to ignore the first part of the file name and begin at "lecture##"? Or even better, can the sort ignore (but not remove) all non-numeric data and sort the array solely by the numbers embedded in the file name?
Thanks for your help.
I think there's no built-in function that do this, but using usort you may accomplish that:
function just_numerical_sort($a, $b)
{
return preg_replace('/[^0-9]/', '', $a) - preg_replace('/[^0-9]/', '', $b);
}
usort($array, 'just_numerical_sort');
the preg_replace returns a copy of $a or $b with all non-numerical characters removed (I haven't tested it, but I think it works).
You should write a script that renames all of the files for you. Don't write some hack to overcome the wrong naming of the files. This will most liekly cause more headaches in the future.
Shoudln't be too hard to write a script that renames the files with a leading 0 for numbers less than 10, or even two leading zeros for numbers less than 10, and one leading zero for numbers between 10 and 99.
filename001.xml
filename002.xml
Then your sort will work perfect.
I have a string. It's a user submitted string. (And you should never ever trust user submitted anything.)
If certain (not unsafe) characters exist in the string, it's supposed to become a multi dimensional array/tree. First I tried splits, regex and loops. Too difficult. I've found a very easy solution with a few simple str_replace's and the result is a string that looks like an array definition. Eg:
array('body', array('div', array('x'), array(), array('')), array(array('oele')))
It's a silly array, but it's very easily created. Now that string has to become that array. I'm using eval() for that and I don't like it. Since it's user submitted (and must be able to contain just about anything), there could be any sort of function calls in that string.
So the million dollar question: is there some kind of var_import, or array_import that creates an array from a string and does nothing else (like mysterious, dangerous calls to exec etc)?
Yes, I have tried php.net and neither of the above _import functions exist.
What I'm looking for is the exact opposite of var_import, becasuse the string I have as input, looks exactly like the string var_export would output.
Any other suggestions to make it safer then eval are also welcome! But I'm not abandoning the current method (it's just too simple).
Using
array('body', array('div', array('x'), array(), array('')), array(array('oele')))
as input, I replaced some chars to make it a valid JSON string and imported that via json_decode.
Works perfectly. If some illegal chars are present, json_decode will trip over them (and not execute any dangerous code).