multidimensional array php flat-file - php

I am upgrading the way my website runs, I have already integrated mant php scripts in pages, but I am trying to develop fully php based site, eg, instead of loading urls:
url/events/event-1
url/events/event-2
^^^ 2 seperate pages
I am trying to load
url/event?url=event-1
this is so I can update 1 page but load different content depending on the
$_GET['url']
parameter.....
what I have so far...
I load url/event?url=dance
it will automatically search a directory for the filename 'dance.txt'
if the file does not exist, it forwards to main events page (url/events)
if the files does exist, it creates a one line string about the event....
the file content is listed like this:
Dance::::18-02-2012::::http://{external link}::::Event Information
the script I have developed to import this data and display it, works fine, but I need a page that will load all events each in a separate div.......
producing this page is simple enough if I can figure out how to arrange the event array data into a multidimensional array for all events...
for individual events, the script simply defines variables as:
$name, $date, $link, $writeup
I have attached sample code of how I do this...
$dir = '/server/htdocs/data/'; // path to dir with all event txt files in
$files = scandir($dir);
$fruit = array_shift($files);
$fruit2 = array_shift($files); // array shifts remove values of '.' and '..'
$line = implode(" ",$files); // back into string for str_replace
// echo $line;
$oldword = ".txt";
$newword = "";
$newline = str_replace($oldword, $newword, $line);
// echo $newline;
$files = explode(" ", $newline); // array of filenames
if (in_array($url, $files)) {
$contents = file_get_contents('data/'.$url.'.txt');
} else { header('Location: http://{url}/events'); }
$info = explode('::::', $contents);
// print_r($info);
$name = $info[0];
$date = $info[1];
$link = $info[2];
$writeup = $info[3];
this works perfectly for individual pages, however, I need to have an array like this:
$events = array ( array ( Name => event-1,
Date => date-1,
Link => link-1,
Writeup => event-info ),
array ( Name => event-2,
Date => date-2,
Link => link-2,
Writeup => event-info ),
array ( Name => event-3,
Date => date-3,
Link => link-3,
Writeup => event-info )
);
this is how I presume the array would be formed, but I need the script to count how many files there are in the /data/ folder, and then (I'm presuming) have a foreach loop so that for each array (event) I can echo:
<div id="content2">
<div class="post">
<center><h2><u>'.$name.' ('.$date.')</u></h2></center>
<p class="postmeta"></p>
<div class="entry">
<CENTER><img src="events/posters/'.$name.'.jpg" height="400" width="500"></center>
<p><p>
<p>'.$writeup.'</p>
<p>'.$name.' Online</p>
</div>
</div><!-- post -->
</div><!-- content2 -->
I know it may seem a complicated way of going around things, but this way my site will be 100% editable via data in txt files, as right now I have to clone existing page, then re-write all content in it for new event!
foreach($files as $key => $value) {
$array[] = array(explode('::::',(file_get_contents('data/'.$files[$key].'.txt'))));
}
print_r($array);
gives me:
Array
(
[0] => Array
(
[0] => Array
(
[0] => 5th-Element
[1] => 11-02-2012
[2] => http://www.5thelementrocks.co.uk/
[3] => 5th Element are a 5 piece classic rock covers band gigging in venues across the North-West and Wales. Our set lists include tracks by all the greats, including AC/DC, The Cult, Muse, Bon Jovi, Nirvana, Whitesnake, The Darkness, Ozzy Osbourne, and many more. </p><p>We are a high quality, high energy, experienced classic rock band who work hard and play hard to get the audience going and to make sure each gig is a pro performance. Whether were playing for a crowd of one or one thousand, we always give 110% to keep you shakin all night long!
)
)
[1] => Array
(
[0] => Array
(
[0] => BBGM
[1] => 25-02-2012
[2] => http://nwb.co/bbgm
[3] => BBGM are four 40-50 something musicians (twin guitars, vocals, bass & drums) who were all in various bands years ago, playing and touring all over the North of England & Europe in the 1980s including working and recording with the now legendary producer Gil Norton.</p><p>In 2007 they got together to form BBGM to gig again. Now an established band on the Northwest circuit we are currently gigging throughout the North West and North Wales playing classic rock covers from the 70's 80's and 90's throwing in one or two original tracks penned over the years.
)
)
[2] => Array
(
[0] => Array
(
[0] => Plastic-Sarcasm
[1] => 18-02-2012
[2] => http://www.facebook.com/pages/PLASTIC-SARCASM/284242054943613?sk=info
[3] => Four lads who are still burning. Having the desire to kick ass every now and then through the music they create.</p><p>Originally formed in 1978 by current member Phil Narayan together with Paul Wynne, Phil Tonge and Baz Yates, the Band played in the Punk Rock scene era in and around Bolton. Having not played guitar (but played drums for a couple of years from 1986 1989) on stage for over thirty years, Phil Narayan couldn't resist a late urge to enjoy the feeling of playing live on stage once again. Regularly practising with PLUM ( joined the band as singer in 1980) who, now plays Bass guitar and sings, the pair set about making the dream happen once again. They recruited Gordon Connolly for an extra guitar who has been playing throughout his life with various bands, in September 2010. Finally, drummer Gag Martin joined up in reply to an advert at the local rehearsal studios in May 2011.</p><p>"Having had 9 practice / Jammin sessions the band played their first gig in Little Lever on 17th December 2011 where all the old Punk songs were revived. The gig was a screaming success and it is the intention to do more gigs in 2012 when the band will gradually introduce their own numbers more and more as gigs go by."
)
)
[3] => Array
(
[0] => Array
(
[0] => Whipcord
[1] => 17-02-2012
[2] => http://www.facebook.com/whipcord
[3] => Doobie Brothers in Bad Brains t-shirts, whistling The Hollies on the way to a Pentagram gig, reading The Wire...it's rock n roll!!</p><p>Whipcord are a stentorian rock n roll power trio from Salford, Manchester UK. Within the noise is a classicist rock feel, drowning in a tar pool of punk rock fury. Being described as the bastard child of Motorhead and Foo Fighters. and that of polished anarchy, not unlike The Whos live shows.
)
)
)
aha nearly done.
ps I would like foreach to list by dates stated in each txt file, it currently lists alphabetically from filenames...

Borrowed a bit of Jribeiro's code to actually read the files into the two-dimensional array.
$items = array();
if ($handle = opendir($dir)) {
while (false !== ($file = readdir($handle))) {
$fp = fopen("$file","r");
while($line = fgets($fp)){
$parts = explode("::::",$line);
$newArr["Name"] = $parts[0];
$newArr["Date"] = $parts[1];
$newArr["Link"] = $parts[2];
$newArr["Writeup"] = $parts[3];
$items[] = $newArr; // add newArr to items
}
fclose($fp);
}
closedir($handle);
}
print_r($items);
Then, to loop through the $items array:
foreach($items as $item){
$name = $item["Name"];
echo "Name is $name<br>";
// etc
}
Although, I'm required to inform you to look into using MySQL to do this as it is much easier, safer, and more powerful than using a flat text file.

If you want the number of files in dir you can try this:
function fileCounter($dir){
$counter = 0;
if ($handle = opendir($dir)) {
//echo "Directory handle: $handle\n";
//echo "Files:\n";
/* This is the correct way to loop over the directory. */
while (false !== ($file = readdir($handle))) {
//echo "<BR>".$counter." - $file";
$counter++;
}
closedir($handle);
}
$counter -= 1; // in order to exclude '.' and '..', as well as start the counter on 1
return $counter;
}

I'm actually not quite sure if i understood your problem correctly.
But at the end you want to store a nested array $events in a flat file and read it back to an array?
I would suggest using serialize to do this, then it's quite simple:
$events = array ( array ( Name => event-1,
Date => date-1,
Link => link-1,
Writeup => event-info ),
array ( Name => event-2,
Date => date-2,
Link => link-2,
Writeup => event-info ),
array ( Name => event-3,
Date => date-3,
Link => link-3,
Writeup => event-info )
);
file_put_contents("/foo/bar",serialize($events)); // BAM, it's in the file :)
//reading it back is equally simple
$events2 = unserialize(file_get_contents("/foo/bar"));

Related

PHP - Multiple Time Difference Calculations

For the life of me I cannot find anywhere on the internet that has any documentation on how to solve my problem. I've seen a massive amount of ways to calculate differences in time but I can not seem to put something together that works for my situation.
I'm currently building a time management/ticket system that is a plugin for WordPress. I am using custom tables and not the WordPress tables. I have a table that contains all the main ticket information and another table that contains all the start/stop times. Once the user marks the ticket as complete it will then take all the start/stop time values and calculate the total time spent and then place that total time value into a "total_time" column in the main ticket table.
I'm querying the database and pulling the start/stop times by using:
$start_times = $wpdb->get_results($start_times_query);
$stop_times = $wpdb->get_results($stop_times_query);
Now I have the information in 2 array's. Is this the way I should be doing this?
The array's give me this (for start times):
Array ( [0] => Array ( [time] => 2016-04-29 12:02:43 ) [1] => Array ( [time] => 2016-04-29 12:04:18 ) [2] => Array ( [time] => 2016-04-29 12:06:07 ) [3] => Array ( [time] => 2016-04-29 12:07:56 ) [4] => Array ( [time] => 2016-04-29 12:10:30 ) [5] => Array ( [time] => 2016-04-29 12:11:59 ) )
(Same format for the end times)
Then I break down the array using:
$startTimes = array_column($startTimes, 'time');
$endTimes = array_column($endTimes, 'time');
Which now gives me this as the array (this one is just the start times, but same format for the end times):
Array ( [0] => 2016-04-29 12:02:43 [1] => 2016-04-29 12:04:18 [2] => 2016-04-29 12:06:07 [3] => 2016-04-29 12:07:56 [4] => 2016-04-29 12:10:30 [5] => 2016-04-29 12:11:59 )
Usually I can do a foreach ($start_time as $time){} to itterate through all the values, but (correct me if I'm wrong) I can't put two array's into the foreach brackets and I can't place another foreach statement in the current one because then it will just return all the times for the second array and only return one value for the first array. I feel like I'm missing something simple, what can I do to accomplish this?
EDIT
Thanks to Scopey I've worked out a while loop, but it's not functioning correctly. Here is what I have:
$startTimes = array_column($startTimes, 'time');
$endTimes = array_column($endTimes, 'time');
while (($startTime = current($startTimes)) !== false && ($endTime = current($endTimes) !== false)) {
$startTimesConv = strtotime($startTimes);
$endTimesConv = strtotime($endTimes);
$totalTime = ($startTimesConv - $endTimesConv)/60/60;
next($startTimes);
next($endTimes);
}
If you want to loop two arrays at the same time, you can use the PHP functions for traversing arrays by manipulating their internal pointer: current, next, reset, end and prev.
You just need to make a while loop:
while (($startTime = current($startTimes)) !== false && ($endTime = current($endTimes) !== false) {
// ... Do things
next($startTimes);
next($endTimes);
}
See the documentation for next and current
To iterate two regular arrays with the same length use for instead of foreach:
$length = count($start_times);
for ($i = 0; $i < $length; $i++) {
$start_time = $start_times[$i]["time"];
$stop_time = $stop_times[$i]["time"];
// do things
}
But in your case, I strongly recommend that calculate the differences in SQL.
I would take a step back and look at the queries themselves. You are trying to do a calculation between two times which are related in your database however, the relationship gets lost by separating the times into two separate arrays. Or at the very least is ambiguously related as an array index.
My pseudocode would look like this:
#For each ticket which is closed
#Get an array (time entries) of arrays (start, stop) (each having it's start and stop time)
#total_time = 0
#For each time entry
#Perform a time calc function to get_time_differnce(start, stop)
#Add the time to Total_time
#Add total_time to ticket record in DB
If you showed some more detail I might be able to expand. (i.e The queries themselves)

Change PHP array

Hi I have built an array and in the final process of finishing the script.
I have been building a web crawler which scans specific links on sites specified. The crawler stores all the links in one page and then inserts them into another array (news_stories) with the links specified in them.
Now the way the new array is structured is like this.
Array
(
[0] => Array
(
[title] => The Qlick
[description] => Qlick
[keywords] => Search Engine, Web, Sexy, Noah Smith
[link] => http://www.theqlick.com/qlickdates.php
)
)
And that is difficult for me to implode and insert into a mysql table. Now my code below uses functions to grab titles, descriptions etc for each link it finds and then inserts them into the new array if they match.
Is there anyway to get this to delete the Array() at the top of the array and just have the array which specifies the title, description etc.
I want the output to look like:
[0] => Array
(
[title] => The Qlick
[description] => Qlick
[keywords] => Search Engine, Web, Sexy, Noah Smith
[link] => http://www.theqlick.com/qlickdates.php
)
Any ideas?
$bbc_values = array('http://www.theqlick.com/festivalfreaks.php', 'http://www.theqlick.com/qlickdates.php');
$news_stories = array();
foreach ($links as $link) {
$item = array(
"title" => Titles($link),
"description" => getMetas($link),
"keywords" => getKeywords($link),
"link" => $link
);
if (empty($item["description"])) {
$item["description"] = getWord($link);
}
foreach($bbc_values as $bbc_value) {
// note the '===' . this is important
if(strpos($item['link'], $bbc_value) === 0) {
$news_stories[] = $item;
}
}
}
$data = '"' . implode('" , "', $news_stories) . '"';
$query =
//CNN algorithm
print_r($news_stories);
PHP foreach() is an iterator, intended to let your programming perform the same action on a collection of data. In the existing design, the *$news_stories* array can contain multiple individual "sub-arrays", with each such "sub-array" being the unit of data you want to insert into your data base.
When you get down to the part about creating queries, you can use something like this:
foreach ($news_stories as $story)
{
/* CREATE AND RUN QUERY USING DATA IN $story */
}
You can use *var_dump()* to look at the contents of a $story array. When you do that, it will probably make sense instantly. PHP foreach() does not care if you have one element or a hundred elements. If you have zero elements, it will not run the code inside the control structure.

Why is a called 'string' invisible to an array?

The file below, can be setup using any JPG file from PhotoShop that has XMP data. In the 'pattern', replace 'eat:' with 'dc:' or any namespace returned from the '$string'.
Calling $string (1) using following array setup it produces a print_r array that looks like: (2)
If you uncomment the line ubove (1a), it will print to the browse, copy & paste into the line below (1a). this should produce an array that looks like: (3)
Why the difference print_r readings, when it's the same string?
How do I get it to behave like (3); ... better yet how do I make it end up like the(4)?
<?php
header("Content-Type: text/html; charset=utf-8");
$filename = "2012-04-24_WestCoast_2.jpg";
echo '<img src="'. $filename . '" alt="'. $filename . '" title="' . $filename . '" width="350" /><p />';
$source = file_get_contents($filename);
$xmpdata_start = strpos($source,'<x:xmpmeta');
$xmpdata_end = strpos($source,"</rdf:Description>");
$xmplenght = $xmpdata_end-$xmpdata_start;
$xmpdata = substr($source,$xmpdata_start,$xmplenght+18);
$string = htmlentities($xmpdata); //(1)
//if (is_string($string)) {
// echo "is a string\n"; //TRUE
//} else {
// echo "is not a string\n";
//}
//$string = print_r("'".$string."';");
// (1a)=====================================
//$string = '<x:xmpmeta xmlns: === Truncated for simplicity ===x="adobe:ns:meta/" x:xmptk="Adobe XMP Core 5.3-c011 66.145661, 2012/02/06-14:56:27 "> <rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"></rdf:Description>';
$pattern = '/eat:(.*?)="(.*?)"/is';
preg_match_all($pattern, $string, $matches);
$group = array($matches[1], $matches[2]);
// foreach($group as &$match);
echo '<pre>';
// print_r ($match);
print_r ($group);
echo '</pre>';
?>
(2)=====================================
// If i just call the '$string', this is what i get:
Array
(
[0] => Array
(
)
[1] => Array
(
)
)
(3)=====================================
// If I uncomment (1), the '$string' that I pasted inside the file, i get this:
Array
(
[0] => Array
(
[0] => Biography
[1] => Title
[2] => object_description
[3] => Medium
[4] => in_height
[5] => in_width
[6] => in_depth
[7] => Dated
[8] => Photograph
)
[1] => Array
(
[0] => American B1942 Castine, Maine
[1] => Reunion Dinner Party at the Slanted Door
[2] => Nancy Freeman, Tim Patterson The Slanted Door San Francisco Calf.
[3] => photography
[4] => 2736
[5] => 3648
[6] => # 240 dpi
[7] => April 24, 2012
[8] => PrimaryImage
)
)
(4)=====================================
// This is what i'm trying to get too:
Biography: American B1942 Castine, Maine
Title: Reunion Dinner Party at the Slanted Door
object_description: Reunion Dinner Party at the Slanted Door
Nancy Freeman, Tim Patterson The Slanted Door San Francisco Calf.
Medium: photography
in_height: 2736
in_width: 3648
in_depth: # 240 dpi
Dated: April 24, 2012
Photograph: PrimaryImage
I'm not clear on what the issue is with the string being set inside or outside of file. It is unclear what you are trying to explain.
The output of the array(3) is caused by the brackets in the Regular Expression. I don't know the exact reason for this, but to get the results you want(4) you could use a loop to join the two arrays in a new array.
Note: What your doing with $group is making an array of arrays. You are not merging the two arrays into one. To merge the arrays you need to iterate through both arrays and merging each element as new element of new array.
example:
for($i=0; $i<match[0].length; $i++){
$result[i] = $match[0][i]. ": " .$match[1][i];
}
Im rusty on my php, but that is the idea for merging the arrays.
--EDIT--
Now that I understand what you are trying to do I see two possible places where problems may occur. First is: are you 100% sure the image you are using contains any meta data in the fields you want? Im not sure of the exact nature of meta data, but I do know there will be the required data set by the computer(what you filtered out with the start and end points), and the custom data. If blank it might not even be included.
Second possible issue is how you are chunking up the meta data. Maybe try writing to Regular Expressions to strip the start and end from the string. Replace everything in front of a set of characters with "" and do a similar expression for the back.
Also the variable you set for $group is the exact same thing that $match was. You took the two arrays that where contained in the array %match and assigned them to an array called $group. Just a FYI. Use the sudo code I posted earlier to design the loop that will actually combine the two arrays into one.
Good Luck. Maybe when I get php set up on testing computer I will play with the code to see what exactly is happening.
Well it looks like i get to answer my own question of "Why it is a called 'string' invisible to an array?".
The answer is: When it's preceded by a call to 'htmlentities()'.
Now I'm not really sure why it happens but it does happen and the instant I went back and checked all my assumptions ... that 'htmlentities()' would clean up the raw string. Commenting out 'htmlentities()' made everything work.
Is this a bug? I personally don't know, and i don't have the necessary experience using PHP to even hazard a guess. What i do know is it drove me up the wall for a week.

I'm trying to parse some text in html with custom nested tags

I would like to parse some text into an array:
My text looks like this:
You've come to the {right; correct; appropriate} place! Start by {searching; probing; inquiring} our site below, or {browse; {search; lookup; examine}} our list of popular support articles.
The third group of words has nested tags. How can I ignore the opening and closing nested tags to achieve an array such as
$tags[0][0] = 'right';
$tags[0][1] = 'suitable';
$tags[0][2] = 'appropriate';
$tags[1][0] = 'searching';
$tags[1][1] = 'probing';
$tags[1][2] = 'inquiring';
$tags[2][1] = 'browse';
$tags[2][2] = 'search';
$tags[2][3] = 'lookup';
$tags[2][4] = 'examine';
Essentially ignoring the nesting of the tags.
Any help would be greatly appreciated.
My only current ideas for this is to traverse the text character by character until I find a { which would increment a "depth" variable. Capture the words in between until I find a } decreasing the depth variable and upon it returning to zero, stop capturing words. I was just wondering if there's a much easier way of doing this. Thanks.
Thanks for your excellent help, I modified it a bit to come up with the following solution.
$code = "You've come to {the right; the correct; the appropriate} place!
Start by {searching; probing; inquiring} our site below, or
{browse; {search; {foo; bar}; lookup}; examine} our list of
popular support articles.";
echo $code."\r\n\r\n";
preg_match_all('/{((?:[^{}]*|(?R))*)}/', $code, $matches);
$arr = array();
$r = array('{','}');
foreach($matches[1] as $k1 => $m)
{
$ths = explode(';',str_replace($r,'',$m));
foreach($ths as $key => $val)
{
if($val!='')
$arr[$k1][$key] = trim($val);
$code = str_replace($matches[0][$k1],'[[rep'.$k1.']]',$code);
}
}
echo $code;
Returns
You've come to {the right; the correct; the appropriate} place! Start by {searching; probing; inquiring} our site below, or {browse; {search; {foo; bar}; lookup}; examine} our list of popular support articles.
You've come to [[rep0]] place! Start by [[rep1]] our site below, or [[rep2]] our list of popular support articles.
My only current ideas for this is to traverse the text character by character until I find a { which would increment a "depth" variable. Capture the words in between until I find a } decreasing the depth variable and upon it returning to zero, stop capturing words. I was just wondering if there's a much easier way of doing this.
That sounds like a reasonable way to do it. Another way to do this is by using a bit of regex, although that might result in a solution that is (far) less readable (and therefor less maintainable) than your own solution.
<?php
$text = "You've come to the {right; correct; appropriate} place!
Start by {searching; probing; inquiring} our site below, or
{browse; {search; {foo; bar}; lookup}; examine} our list of
popular support articles. {the right; the correct; the appropriate}";
preg_match_all('/{((?:[^{}]*|(?R))*)}/', $text, $matches);
$arr = array();
foreach($matches[1] as $m) {
preg_match_all('/\w([\w\s]*\w)?/', $m, $words);
$arr[] = $words[0];
}
print_r($arr);
?>
would produce:
Array
(
[0] => Array
(
[0] => right
[1] => correct
[2] => appropriate
)
[1] => Array
(
[0] => searching
[1] => probing
[2] => inquiring
)
[2] => Array
(
[0] => browse
[1] => search
[2] => foo
[3] => bar
[4] => lookup
[5] => examine
)
[3] => Array
(
[0] => the right
[1] => the correct
[2] => the appropriate
)
)

Generic PHP Match Template with String

is there a function that will allow me to do the following:
$template = "{name}:{city}-{state}"
$string = "Tom:Some CityPlace-CA"
$out = function_I_am_looking_for($template,$string);
when $out returns
Array(
[name] => Tom
[city] => Some CityPlace
[state] => CA
)
Does such a function exist?
-------- EDIT -----------
So the people have spoken, and since I dont like seeing something like this die, I will conclude. No built in function exists, however I did mock up one, and it does work. Feel free to refine, please comment you edits.
function genaric_match($template,$string,$varStart="{{",$varEnd="}}"){
$template = str_replace($varStart,"|~|`",$template);
$template = str_replace($varEnd,"`|~|",$template);
$t=explode("|~|",$template);
$temp="";
$i=0;
foreach ($t as $n=>$v){
$i++;
if (($i==count($t)||($i==(count($t)-1)&&$t[$n+1]==""))&&substr($v,0,1)=="`"&&substr($v,-1)=="`"){
//Last Item
$temp.="(?P<".substr($v,1,-1).">.++)";
}elseif(substr($v,0,1)=="`"&&substr($v,-1)=="`"){
//Search Item
$temp.="(?P<".substr($v,1,-1).">[^".$t[$n+1]."]++)";
}else{
$temp.=$v;
}
}
$temp="~^".$temp."$~";
preg_match($temp, $string, $matches);
return $matches;
}
This example
print_r(genaric_match("{{name}}:{{city}}-{{state}}","Tom:Some CityPlace-CA"));
Returns
Array
(
[0] => Tom:Some CityPlace-CA
[name] => Tom
[1] => Tom
[city] => Some CityPlace
[2] => Some CityPlace
[state] => CA
[3] => CA
)
Yes, it's called preg_match. But you obviously need to write a regex for it. (If your question is, whether there is a magic recognize-any-pattern-without-even-knowing-it's-syntax function, then the answer is: No.)
preg_match('~^(?P<name>[^:]++):(?P<city>[^-]++)-(?P<state>.++)$~', $string, $matches);
var_dump($matches);
There's no such function in PHP "out of the box", but it would be fairly trivial to write one, as there are quite a few functions such as...
explode
preg_replace
parse_string
etc.
...that you could use to create one.
However, it has to be said that using PHP (which is to a large extent a template language) to create another template language seems an odd choice.

Categories