I'm having trouble with the executing the command mailq and turning it's output into values in a multidimensional array.
$results = array();
exec('/usr/bin/mailq', $mailQresult);
foreach ($mailQresult as $key => $mailqLine) {
$res = preg_match('/^([A-Z0-9]{1,20})\s+([1-9][0-9]*)\s+((Mon|Tue|Wed|Thu|Fri|Sat|Sun)\s+[A-Za-z]{3}\s+[0-9]{2}\s+[0-9]{2}\:[0-9]{2}\:[0-9]{2})\s*$/', $mailqLine, $matches);
if ($res) {
// Insert message ID and other data into the object.
// It will be competed afterwards.
$mailqArray = array(
'id' => $matches[1],
'size' => intval($matches[2]),
'date' => strftime($matches[3]),
'sender' => $matches[5],
'failed' => false,
'recipients' => $matches[4]
);
}
}
The output of mailq includes white space and returns and looks a bit like this:
ID SIZE DAYNAME MONTH DAY HOUR:MINUTES:SECONDS sender#address.com [new line here]
(Host or domain name not found. Name service error for name=address.com type=MX: Host not found, try again) [new line here]
recipient#address.com
so the the error message and the recipient end up in different keys.
I know that I could use shell_exec to get the output of mailq as one string but I have no idea then how to write the regular expression that will create a multidimensional array.
I might be approaching this wrong. Any advice is extremely welcome!
You could check the next item in the array to see if it contains a new messageid and other indicators. Probably a for loop instead of a foreach.
Related
I have a json array that looks like this:
{"server-host-01":{"API":"Good","JETS":"Good","HTTPD":"Good","DISK":"23% Used","CPU":"WARNING: Avg idle at: 98% "},"server-host-02":{"DISK":"18% Used","CPU":"Avg idle at: 99% "}}
I have a key then inside that key another array of key:values and then another key with the same setup of key:values inside.
In my php script i am assigning the json file to the variable of $files and then using json_decode to turn it into a php array (i think)
$files = (my_json_file.json);
$string = file_get_contents($file);
$json_a = json_decode($string, true);
Now i have the array in php i would like to print the main keys out and then print the key:values of the keys. They will be going into a html table but specially im looking for help printing out the values as i need them before i worry about the html part.
Viewing the JSON contents
You have a JSON encoded array which contains two arrays inside of it as below (which I obtained via this link):
array (
'server-host-01' =>
array (
'API' => 'Good',
'JETS' => 'Good',
'HTTPD' => 'Good',
'DISK' => '23% Used',
'CPU' => 'WARNING: Avg idle at: 98% ',
),
'server-host-02' =>
array (
'DISK' => '18% Used',
'CPU' => 'Avg idle at: 99% ',
),
)
If you wanted to view all values pertaining to server-host-01 you could do e.g.
var_dump($json_a['server-host-01']);
If you wanted only the CPU status you could to do e.g.
$server_host_01_CPU_Status = $json_a['server-host-01']['CPU'];
var_dump($server-host-01-CPU-Status);
Example code
Here's an example of the above in action:
<?php
$json = json_decode('{"server-host-01":{"API":"Good","JETS":"Good","HTTPD":"Good","DISK":"23% Used","CPU":"WARNING: Avg idle at: 98% "},"server-host-02":{"DISK":"18% Used","CPU":"Avg idle at: 99% "}}');
$server_host_01_CPU_Status = $json['server-host-01']['CPU'];
var_dump($server_host_01_CPU_Status);
foreach($json['server-host-02'] as $key => $value)
{
var_dump("$key = $value");
}
?>
Other notes
Your line $files = (my_json_file.json); is invalid PHP. I'm not 100% sure what you're trying to achieve but firstly:
1) my_json_file.json isn't wrapped in quotes so PHP is treating it as a constant variable rather than a string (and this throws an error too -- turn PHP server errors on to see it)
2) The unquoted string my_json_file.json is wrapped in parenthesis which doesn't even do anything in this case.
Assuming what you actually want is an array of file names to then open you'd want something like this:
$files = ['my_json_file.json'];
foreach($files as $file)
{
$contents = file_get_contents($file);
$json = json_decode($contents, true);
// foreach($json as $key => $value) { ...
}
I would highly recommend checking out this tutorial for the basics on handing JSON data in PHP.
My POST form sends a value &messages=12,11
I get it using: $messages = $ep->remove($_POST["messages"]);
And my SQL string is:
$query = $db->prepare("DELETE FROM messages WHERE messageID IN ('".$messages."') AND accountID=:accountID");
$query->execute([':accountID' => $accountID]);
And the error appears....
<b>Fatal error</b>: Uncaught exception 'PDOException' with message 'SQLSTATE[22007]: Invalid datetime format: 1292 Truncated incorrect DOUBLE value: '12,11'' in /var/www/vhosts/xxx.xxx/xx/xxx/xx/xxxx/messages.php:17
This code deletes multiple messages from the database. But don't works for me. Any fix?
Remove the quotation marks:
$query = $db->prepare("DELETE FROM messages WHERE messageID IN (".$messages.") AND accountID=:accountID");
Otherwise the value you're sending is 12,11 (which isn't a number as per your database definition), as opposed to 12 and 11, which are both numbers.
Finally, this particular query structure is open to SQL injection. You may want to either sanitise the $messages variable (since it can only include numbers), or create a prepared statement.
For this example, sanitising could work as follows:
$messages = preg_replace('/[^0-9,]/', '', $messages);
//Removes all characters besides numbers and commas
You could also ensure that the list of numeric message IDs always matches the following regex pattern:
$\d+(?:,\d+)*$
That is, the parameter should always be some number, followed by an optional quantity of ,\d+ terms
if (!preg_match("/^\d+(?:,\d+)*$/", $messages)) {
// throw an exception, you are being injected
}
Just to add to the other answer, here is a way to properly prepare all the values
$array = explode(',', '1,2,3,4,5,6');
$keys = preg_replace('/(.+)/', ':v\1', array_keys($array));
print_r($keys);
$sql = "DELETE FROM messages WHERE messageID IN ( ".implode(',', $keys)." ) AND accountID=:accountID";
print_r($sql);
$params = array_combine($keys,$array);
$params['accountID'] = 'foo';
print_r($params);
//$stmt->execute($params);
Output
//print_r($keys);
Array
(
[0] => :v0
[1] => :v1
[2] => :v2
[3] => :v3
[4] => :v4
[5] => :v5
)
//print_r($sql);
DELETE FROM messages WHERE messageID IN ( :v0,:v1,:v2,:v3,:v4,:v5 ) AND accountID=:accountID
//print_r($params);
Array
(
[:v0] => 1
[:v1] => 2
[:v2] => 3
[:v3] => 4
[:v4] => 5
[:v5] => 6
[accountID] => foo
)
Sandbox
It was way too much for a comment.
Basically it takes the keys and using preg replace we can take the sequential number and add a string to it (placeholders have to start with a alpha). Technically the : in the array for execute is optional.
Then we can put that into the query, as it's all generated by PHP because the keys are made from explode. If you have keys from POST, don't use those instead use array_keys(array_values($array)) array values will make the array numerically indexed, then you use those keys.
Next using array combine we can merge those keys back into the original values and put that array into execute
In this case You can do it just with a regex, but I wanted to show something that was useful for more complex cases of IN.
I've an array titled $request as follows :
Array
(
[invite_emails] => suka#gmail.com, swat#gmail.com
[page_id] => 322
[ws_url] => http://app.knockknot.com/api/group/sendInvitation
)
After using json_encode($request) I got following output:
{
"invite_emails": "suka#gmail.com, swat#gmail.com",
"page_id": "322",
"ws_url": "http://app.knockknot.com/api/group/sendInvitation"
}
But actually I want the JSON object as follows :
{
"page_id": 322,
"invite_emails": [
"suka#gmail.com",
"swat#gmail.com"
],
"ws_url": "http://app.knockknot.com/api/group/sendInvitation"
}
How should I manipulate the array in PHP in order to get the above desired JSON object?
Please someone help me.
Split the list of emails using the comma:
$array["invite_emails"] = preg_split("#\s*,\s*#", $array["invite_emails"]);
I personally prefer using callback functions for readability and possibilities. To your purpose, array_walk should fit:
<?php
// reproducing array
$request = array(
"invite_emails" => "suka#gmail.com, swat#gmail.com",
"page_id" => 322,
"ws_url" => "http://app.knockknot.com/api/group/sendInvitation"
);
// callback finds a comma-separated string and explodes it...
array_walk($request, function (&$v,$k) {if ($k == 'invite_emails') $v = explode(", ", $v);});
// ... and then encode it to JSON
json_encode($request);
// testing
print_r($request);
OUTPUT:
{
"invite_emails":[
"suka#gmail.com",
"swat#gmail.com"
],
"page_id":322,
"ws_url":"http://app.knockknot.com/api/group/sendInvitation"
}
You are free to change the field if your needs changes, and even suppress it to be used with any field of the array.
Use PHP explode for example:
$array['invite_emails'] = explode(',',$array['invite_emails']);
To avoid spaces use preg_split (source):
$array['invite_emails'] = preg_split("/[\s,]+/", $array['invite_emails']);
This entry:
[invite_emails] => suka#gmail.com, swat#gmail.com
should be an array (currently, it is a string) in PHP, then in JSON it will look like you want it.
I have an array that is filled with different sayings and am trying to output a random one of the sayings. My program prints out the random saying, but sometimes it prints out the variable name that is assigned to the saying instead of the actual saying and I am not sure why.
$foo=Array('saying1', 'saying2', 'saying3');
$foo['saying1'] = "Hello.";
$foo['saying2'] = "World.";
$foo['saying3'] = "Goodbye.";
echo $foo[array_rand($foo)];
So for example it will print World as it should, but other times it will print saying2. Not sure what I am doing wrong.
Drop the values at the start. Change the first line to just:
$foo = array();
What you did was put values 'saying1' and such in the array. You don't want those values in there. You can also drop the index values with:
$foo[] = 'Hello.';
$foo[] = 'World.';
That simplifies your work.
You declared your array in the wrong way on the first line.
If you want to use your array as an associative Array:
$foo=Array('saying1' => array (), 'saying2' => array(), 'saying3' => array());
Or you can go for the not associative style given by Kainaw.
Edit: Calling this on the not associative array:
echo("<pre>"); print_r($foo); echo("</pre>");
Has as output:
Array
(
[0] => saying1
[1] => saying2
[2] => saying3
[saying1] => Hello.
[saying2] => World.
[saying3] => Goodbye.
)
Building on what #Answers_Seeker has said, to get your code to work the way you expect it, you'd have to re-declare and initialise your array using one of the methods below:
$foo=array('saying1'=>'Hello.', 'saying2'=>'World.', 'saying3'=>'Goodbye.');
OR this:
$foo=array();
$foo['saying1'] = "Hello.";
$foo['saying2'] = "World.";
$foo['saying3'] = "Goodbye.";
Then, to print the contents randomly:
echo $foo[array_rand($foo)];
So I've the following situation: A process is piping huge amounts of data into a PHP script I'm using to parse and then store some info in a DB.
The input data is a multiline string, but what really matters for me is to find particular key words and then say that the input data is an error of the type 1 to n.
I've an array like this:
$errors = [
1 => [
"error 4011",
"clp-no",
],
2 => [
"error 4012",
"clp-nf",
"0010x100"
],
];
The idea is to state what key is the error - the array keys are the error numbers. Currently I've this piece of code to take care of the situation:
$errorId = 25; // Default error for undetected / others
foreach ($errors as $ierrorId => $matches) {
foreach ($matches as $match) {
if (mb_stripos($raw, $match) !== false) {
$errorId = $ierrorId;
break 2;
}
}
}
This code works fine, however, it looks like there is a bottleneck when I look at resource usage when the processes dump information to it... (usually around 10 or 20 strings to be processed by running that 20 times.)
What is the recommended way to do what I'm trying to accomplish with the minimum resource usage?
The output of the code is the ID of the error. The ID of the error is one of the numeric keys of the $errors array.
This code basically groups possible messages that are in the reality the same error and then gives me a unique error ID.
Thank you.
Example of the $raw input this parses:
[0]: error 4011 processing request
.
No input data: clp-nf
.
This is an automated message from the PTD daemon
=> Error: 0010x111.
And some others, the bottom line is: The format can change and I can't rely on position and stuff, it must try to find one of the strings on the array and then return the array key. For instance the second message will output 2 because clp-nf can be found on the second position of the array.
I did a little benchmarking with different functions to find text strings.
mb_stripos (case insensitive)
mb_strpos (case sensitive)
mb_strpos and strtolower on both the string to be searched and the error strings
I also tried the nested array structure you posted above, and a flat error list with the keys being the error strings and the values being the error number. Here are the results I got from running 20,000 reps on a set of sample strings (all returned the same set of errors) with an array of six different error strings, including one error string with non-ASCII characters:
[nested_stripos] => 178.60633707047s
[nested_strpos] => 19.614015340805s
[nested_strpos_with_strtolower] => 25.815476417542s
[flat_stripos] => 177.30470108986s
[flat_strpos] => 18.139512062073s
[flat_strpos_with_strtolower] => 24.32790517807s
As you can see, using mb_stripos is very slow in comparison with mb_strpos. If you don't know what case the errors will be in, it is much quicker to convert everything to lowercase than to use mb_stripos. Using a flat list is marginally faster than the nested arrays over 20,000 reps but there is unlikely to be a noticeable difference unless your raw input is large.
I didn't test preg_match as it is fairly well known that regular expressions are slower than string matching.
If you start recording the error string that was matched (e.g. error 4012 or 0010x001), you can build up frequency tables and order your error strings by which occur the most frequently.
This was the fastest function:
# lines: an array of text strings, including several with non-ASCII characters
# $err_types: data structure holding the error messages to search for (see below)
function flat_strpos($err_types, $lines){
$list = array();
foreach ($lines as $l) {
$err = 25;
foreach ($err_types['flat'] as $e => $no) {
if (mb_strpos($l, $e) !== false) {
$err = $no;
break;
}
}
$list[] = "ERR $err; content: " . mb_substr($l, 0, 100);
}
return $list;
}
And for reference, the $err_type data structure:
$err_types = [
'flat' => [
'error 4011' => 1,
'clp-no' => 1,
'error 4012' => 2,
'clp-nf' => 2,
'0010x100' => 2,
'颜色' => 3
],
'nested' => [
1 => [
'error 4011',
'clp-no'
],
2 => [
'error 4012',
'clp-nf',
'0010x100'
],
3 => [
'颜色'
]
]
];