Extract data from a file PHP - php

I have this array $awstat that I extacted from an awstat file, an withing $awstat I have this that I need:
BEGIN_TIME 24
0 3245 9955 143463426 8047 13601 475741423
1 3122 9131 146244440 7579 12936 507921700
2 2639 5706 95369716 7351 11987 490330698
3 1917 4062 79234871 8245 13009 579453498
4 1757 4263 65580607 7887 11437 454870321
5 1723 4022 44682383 6888 10263 326819624
6 1876 4677 56964771 7339 11242 355385677
7 2796 8473 120152521 7770 12176 362904239
8 4227 13791 196173677 7421 12196 366706352
9 7984 25965 375376297 8398 13883 406545549
10 14605 34418 434054375 7183 13341 380773129
11 15533 41259 559938996 7123 12690 372426426
12 17495 40043 505139834 7432 13402 518541077
13 15815 34170 385108531 6519 12390 396494926
14 16330 41073 508838859 6761 12318 348417806
15 19093 44058 483568307 7692 13583 454365520
16 30429 59672 577852398 8273 13231 473134295
17 25094 48897 478246556 8207 12898 476038603
18 19136 42665 482073005 8087 12983 468300958
19 28849 46228 371229572 7721 12688 471632281
20 14068 30981 341103557 7832 13251 417443822
21 14727 33458 394841797 7575 12644 388811384
22 13480 31364 365096742 7460 13114 411771572
23 7189 19744 272606100 6643 12398 397762547
END_TIME
So I tried this and it doesn't seem to work!
preg_match("/BEGIN_TIME(.*)END_TIME/is", $awstats, $matches);
$time = $matches[0] ;
var_dump($time); // it displays "NULL"
Any solution for this? Thanks!

Not so much an answer, more of an opinion.
Using regular expressions here is overkill.
Something as simple as this will do:
$lines = file("awstats.output");
$lines = array_slice(1); // remove first line
$lines = array_slice(0, -1); // remove last line
foreach ($lines as $line) {
$data = explode(" ", $line);
// handle data
}

You can match linebreaks with:
([^\n]*\n+)+
So this should work:
preg_match("/BEGIN_DAY([^\n]*\n+)+END_DAY/is", $awstats, $matches);

$time = file_get_contents('awstat.log');
$time = preg_replace('/BEGIN_TIME(.*?)END_TIME/sim', '$1', $time);

Related

Parsing input text to array and sum values

Hello :) I am stuck in my mini-app developing. I have following text, copied from 3rd party web page:
Type A GZ 600 11.09.2021 12:00 OST 9
Type A GZ 601 11.09.2021 13:20 ADS 1
Type A GZ 602 11.09.2021 21:35 OCS 1
Type A GZ 603 11.09.2021 14:50 CSE 10
Type B GZ 600 11.09.2021 12:00 OST 5
Type B GZ 601 11.09.2021 13:20 ADS 3
Type B GZ 602 11.09.2021 21:35 OCS 6
Type B GZ 603 11.09.2021 14:50 CSE 12
I need to parse it to following format:
$s = 10, $ns = 11, $bs = 26, like:
echo "S:" . $s . " NS:" . $ns . " BS:" . $bs; // Output: S:10 NS:11 BS:26
where:
$fa = array("OCS", "CSE"); is array of codes
$ns is sum of Type A last column numbers, which 5 column 3-letter code is in the array,
$s is sum of Type A last column numbers, which 5 column 3-letter code is not in the array
$bs is just sum of Type B last column numbers
My code now is following:
if(!empty($_POST['indata'])){
$in_data = $_POST['indata']; // Get POST data
$fa = array("OCS", "CSE"); // Make array
$ns = 0; // Init ns value
$s = 0; // Init ss value
foreach(explode("/n",$in_data) as $line){ // Divide text to lines
$info[] = explode(" ", $line); // Divide line to values and put them to array
print_r($info); //Show input for test purposes
if(in_array($info[4], $fa)) { // Check, if 4th array value (code) is in array
$ns = $ns + $info[5]; // plus to $ns, if yes
} else {
$s = $s + $info[5]; // plus to $s, if no
}
unset($info); // clear array for next usage
}
}
But it seems not cutting line into array. It just shows me lines, not dividing to array. I am using Summernote text editor, it sends data as rows.
Because you're using $info[] = ... you get a 2 levels deep array instead of 1 level as your code is expecting. $info[] = ... basically means "Add the right hand side to $info as one element". So if the right hand side is a string and $info was empty before you'd get [0 => "my string"]. If the right hand side was an array you'd get [0 => [0 => "my", 1 => "array"]].
Do you see what I am getting at? Your code is adding one element to $info, never more than that. So to access anything in $info the first part needs to be $info[0]. But the code looks for the 4th and 5th elements, and they'll never be there. On the other hand, if you'd look for the 4th element inside the 1st one.. That is, $info[0] for the 1st element, and then the 4th inside it: $info[0][4], then you get what you're looking for.
if(!empty($_POST['indata'])){
$in_data = $_POST['indata']; // Get POST data
$fa = array("OCS", "CSE"); // Make array
$ns = 0; // Init ns value
$s = 0; // Init ss value
foreach(explode("\n",$in_data) as $line){ // Divide text to lines
$info[] = explode(" ", $line); // Divide line to values and put them to array
if(in_array($info[0][4], $fa)) { // Check, if 4th array value (code) is in array
$ns = $ns + (int) $info[0][5]; // plus to $ns, if yes
} else {
$s = $s + (int) $info[0][5]; // plus to $s, if no
}
unset($info);
}
}
var_dump($ns, $s); // int(29) int(18)
Version 2. Do away with one level in $info as mentioned earlier:
foreach(explode("\n",$in_data) as $line){
$info = explode(" ", $line);
if(in_array($info[4], $fa)) {
$ns = $ns + (int) $info[5];
} else {
$s = $s + (int) $info[5];
}
}
Alternative version, regexp:
foreach(explode("\n",$in_data) as $line){
$info = preg_split('/\s{4,}/', $line); // Split when 4 or more spaces
if(in_array($info[3], $fa)) {
$ns = $ns + (int) $info[4];
} else {
$s = $s + (int) $info[4];
}
}
That way you don't get any "junk columns" :).
Edit: I think it was PHP 7.1 that introduced some more "strictness" regarding adding values of different types, strings + numbers that is. A notice is issued, "A non well formed numeric value encountered". But if the string is cast/converted as a number before summing PHP will accept it. Casting can be done by adding (int) in front of the string value. (Provided it contains an integer value, of course, otherwise it needs to be cast differently)
After parsing the lines of text with regex, you only need to iterate the matches and conditionally sum the groups.
Code: (Demo)
$text = <<<TEXT
Type A GZ 600 11.09.2021 12:00 OST 9
Type A GZ 601 11.09.2021 13:20 ADS 1
Type A GZ 602 11.09.2021 21:35 OCS 1
Type A GZ 603 11.09.2021 14:50 CSE 10
Type B GZ 600 11.09.2021 12:00 OST 5
Type B GZ 601 11.09.2021 13:20 ADS 3
Type B GZ 602 11.09.2021 21:35 OCS 6
Type B GZ 603 11.09.2021 14:50 CSE 12
TEXT;
$fa = ["OCS", "CSE"];
$result = ['s' => 0, 'ns' => 0, 'bs' => 0];
preg_match_all(
'/^Type ([AB]).+([A-Z]{3})\h+(\d+)$/m',
$text,
$matches,
PREG_SET_ORDER
);
foreach ($matches as $m) {
if ($m[1] === 'B') {
$result['bs'] += $m[3];
} elseif (in_array($m[2], $fa)) {
$result['s'] += $m[3];
} else {
$result['ns'] += $m[3];
}
}
var_export($result);
Output:
array (
's' => 11,
'ns' => 10,
'bs' => 26,
)

Get value of multidimensional array in array

I have below values in formsubmit,
items[0][item_name]: Test
items[0][item_description]: testing1
items[0][item_price]: 11
items[0][item_group]: 18
items[0][item_code]: 11
items[0][item_is_active][]: 1
items[1][item_name]: test2
items[1][item_description]: test
items[1][item_price]: 12
items[1][item_group]: 18
items[1][item_code]: 12
items[1][item_is_active][]: 1
and here is serverside DB entry in laravel,
$items_data = $request->items;
foreach ($items_data as $i) {
$items = new Menuitems; //Must be reinit to reiterate all entries
$items->item_name = $i['item_name'];
$items->item_description = $i['item_description'];
$items->item_price = $i['item_price'];
$items->item_group = $i['item_group'];
$items->item_code = $i['item_code'];
$items->item_is_active = $i['item_is_active'];
$items->save();
}
It works fine all entries except for item_is_active because it has one more [ ] in form input,
How can I add item_is_active in foreach loop? should it have one more foreach loop inside?
Below is formsubmit values when some checkboxes are not selected,
items[0][item_name]: Capachno
items[0][item_description]: best
items[0][item_price]: 12
items[0][item_group]: 17
items[0][item_code]: 11
items[0][item_is_active][]: 1
items[1][item_name]: Lambc
items[1][item_description]: sdf
items[1][item_price]: 34
items[1][item_group]: 17
items[1][item_code]: 12
items[1][item_is_active][]: 1
items[2][item_name]: tasto
items[2][item_description]: ewr
items[2][item_price]: 12
items[2][item_group]: 17
items[2][item_code]: 13
items[3][item_name]: hingo
items[3][item_description]: 123
items[3][item_price]: 123
items[3][item_group]: 17
items[3][item_code]: 32

Multiple comparison and edit file

Here is my $file1 structure (there are thousands of like that groups):
Group id_7653
{
type register
sub_name 155
1 3123 1 12
2 3124 1 8
3 3125 1 4
4 3126 1 12
5 3127 1 8
6 3128 1 4
.....
}
Group id_8731
{
type register
sub_name 155
1 4331 1 12
2 4332 1 8
3 4333 1 4
4 4334 1 12
5 4335 1 8
6 4336 1 4
.....
}
And here is my $file2 structure (again, there are thousands of defined values)
.....
3123 Spada+1
3124 Spada+2
3125 Spada+3
3126 Spada+4
3127 Spada+5
3128 Spada+6
3129 Spada+7
3130 Spada+8
.....
And here is my Worker script that makes, compares $file1 and $file2.
<?php
//read the first file in as a string
$file1 = file_get_contents("dataparser\names1.txt");
//read the second file in as an array
$file2 = file("dataparser\names2.txt");
//index from file2 that we are going to build
$file2Index = array();
foreach($file2 as $line){
//split the line
$line = explode("\t", $line, 2);
//validate the line, should be only 2 values after explode and first should be a number
if(count($line) == 2 && is_numeric($line[0])){
//add to index
$file2Index[$line[0]] = $line[1];
}
}
//now get all the values from file1 that we want (second column)
preg_match_all('/^\s*\d+\s*(\d+)\s*\d+\s*\d+\s*$/m', $file1, $matches);
$file1Values = array_unique($matches[1]);
//loop over the matches from column 2
foreach($file1Values as $value){
//check if the key doesn't exist
if(!isset($file2Index[$value])){
//echo error message
echo "Value {$value} does not exist in file2<br>";
}
}
?>
What makes that script:
Compares $file1 and $file2 and shows me which values are not defined in $file2
So far, everything works okay.
I want to extend that my script a little bit, so I want to replace that {$value} with my $file2 structure.
This time, I don't want to check that value, I want replace it directly from $file1 value. (Spada etc...)
Which paths I should follow...? Can I get some examples please...

PHP Grab a certain word and ignore the rest in a string

I am trying to grab only usernames in a list of sentences of about 30 lines long. I am able to get it to grab the usernames and everything afterwards but I dont want to get everything after the username.
test.txt
[India] Hagiwara has been inactive for 33 days (last seen: Sun Jan 25 23:35:35 2015).
[India] Psyborg has been inactive for 35 days (last seen: Fri Jan 23 18:43:58 2015).
[Echo] Pela has been inactive for 31 days (last seen: Tue Jan 27 20:00:30 2015).
PHP
$data = file('test.txt');
foreach ($data as $lines) {
if (($pos = strpos($lines, "]")) !== FALSE) {
$string = substr($lines, $pos+1);
}
echo $string . '<br />';
}
Output
Hagiwara has been inactive for 33 days (last seen: Sun Jan 25 23:35:35 2015).
This may be more than you expected, but here is a way to avoid regex.
$string = substr($lines, $pos+2);
$string = substr($string, 0, strpos($string, ' '));
$username = explode(' ',$lines)[1];
Given your example strings and based on the assumption that a username will never contain whitespace characters:
<?php
$input_line = "[India] Hagiwara has been inactive for 33 days (last seen: Sun Jan 25 23:35:35 2015).";
if (preg_match("/\[.+\]\s*(\S+)\s*.*/", $input_line, $output_array) == 1) {
echo $output_array[1];
}
?>
Will print out "Hagiwara".
The Regex to do this isn't so complicated. It's more bulletproof imho
$str1 = '[India] Hagiwara has been inactive for 33 days (last seen: Sun Jan 25 23:35:35 2015).';
$str2 = '[India] Psyborg has been inactive for 35 days (last seen: Fri Jan 23 18:43:58 2015).';
$str3 = '[Echo] Pela has been inactive for 31 days (last seen: Tue Jan 27 20:00:30 2015).';
$strs = array($str1,$str2,$str3);
foreach ($strs as $key => $val) {
//strips the initial bracketed string from the beginning of the line
$trimmed_val = preg_replace("/^\[\w+\]\s/",'',$val);
//grabs the first word from the trimmed string (user in this case)
preg_match("/^\w+\s/",$trimmed_val,$users);
//prints out a list of users for demonstration
echo $users[0] . '<br/>';
}

php format input data and put it into multiple arrays

i'm trying to put input (below) into multiple arrays (or maybe its simpler into one array) to finally export it into mysql table, input data goes like:
0 98
77 09
0 12
0 98234
32 0
0 1
0 0
345 32
34 9
6437 34
789 0
0 0
.
.
34 0
my simple code ($run_txt_filter1 is input):
if ( $counted == 64)
{
echo "line's number: ".$counted;
//echo $run_txt_filter1;
for ($modi = 0; $modi <= 15; $modi++)
{
for ($simhi = 1; $simhi <= 4 ; $simhi++)
{
$exploded=explode(" ", $run_txt_filter1);
var_dump($exploded)." \n";
}
}
}
Why var_dump keeps saying the id from 0-64 ? (there always should be 64 input lines).
What a really want to achieve is:
array0=(0, 77, 0, 0)
array1=(98, 09, 12, 98234)
array2=(32, 0, 0, 345)
.
.
array30=(0, 12, 0, 34)
array31=(0, 0, 0, 0)
thanks in advance
try to separate your explode for the next line and explode for the white space. cause on your code above it's reading the whole string as one causing your program to store it on a single array. so it would be a nested loop by then. :)
Considering this input:
$in = <<<IN
0 98
77 09
0 12
0 98234
32 0
0 1
0 0
345 32
34 9
6437 34
789 0
0 0
IN;
This algorithm solves your problem i think:
$final_array = array();
$offset = 0;
foreach(preg_split("/(\r?\n){2,}/",$in) as $block){
foreach(preg_split("/(\r?\n)/",$block) as $line){
foreach(preg_split("/\s+/",$line) as $column => $value){
if($value=='') continue;
if(!isset($final_array[$offset+$column]))
$final_array[$offset+$column] = array();
$final_array[$offset+$column][]=$value;
}
}
$offset = count($final_array);
}
print_r($final_array);
try something similar to this one I'm not sure if this would work:
inputs:
$inputs = "0 98
77 09
0 12
0 98234
32 0
0 1
0 0
345 32
34 9
6437 34
789 0
0 0
.
.
34 0";
code:
$run_txt_filter1 = explode("\n", $inputs);
if(count($run_txt_filter1) == 64)
{
foreach($run_txt_filter1 as $input)
{
$exploded = explode(' ', $input);
print_r($exploded);
}
}
The "\n" is the next line for windows but it's different on linux its "\r" I'm not sure if it would work you may also try the combination as
explode("\r\n", $inputs);
but just a try if the next line won't work I think you could use some other way to separate each set of values either user other type of characters like ',',';',':' etc. :)

Categories