PHP blog (iterating through array data) - php

I'm not especially experienced in PHP, but I've been trying to create a basic blog for a friend's website. I thought the easiest thing to do for now would be to use static files, so I'm using XML to store the blog entries. I've managed to set it up perfectly in that I can display the posts as I want them. However, I now want a nav bar which will allow me to select posts based on date, as most blogs have. The files are simply named 1.xml, 2.xml, 3.xml etc. so I can iterate through them. Here's the code that shows how the data array is organised (it's an array within an array so that the first level will be equivalent to the number in the filename +1). So I'm having a lot of trouble working out how I can create the nav bar (ul, li etc.) from this data. Presumably I'd need years to be unique and then the months in the years to be unique and also with the days, then I can have each title (obviously a link) come under the proper date.
$data = array();
for ($i = 1; $i <= $numberOfPosts; $i++) {
$filename = './blogentries/' . $i . '.xml';
if (!file_exists($filename))
throw new Exception();
$blogentry = simplexml_load_file($filename);
$title = $blogentry->title;
$dateD = $blogentry->date->day;
$dateM = $blogentry->date->month;
$dateY = $blogentry->date->year;
if (strlen($dateY) === 2) $dateY = '20' . $dateY;
$entryParagraphs = $blogentry->entry->children();
$data[] = array(
(string)$title,
array(
(string)$dateY,
(string)$dateM,
(string)$dateD
),
$entryParagraphs
);
}
Thanks for any help you can give. And sorry if I've not been as eloquent as I might have been, I hope you'll forgive my relative ignorance!

From what I understand, I will go with this type of solution :
First of all, if you do know a little bit of OOP, please create an Article class.
After that, here is what I would do for what you are asking :
Instead of creating an array (which should in fact be a class, (the first array, I don't know if you do realize that), I would do this array :
$data[$dateY][$dateM][$dateD]=$blogentry;
Then, you have all your articles classified by Year, then month, then day, so it becomes really simple to end with your request.
edit :
When I said it should be a class, I'm talking about this array :
array(
(string)$title,
array(
(string)$dateY,
(string)$dateM,
(string)$dateD
),
$entryParagraphs
)
It's typically what a class is designed for.

Related

Filter a php array to only elements that have a matching value to $name in $data

I have a php script getting all folders in a posts folder and making them into a list.
I have a $postinfo_str variable assigned to a json file for each folder which I am using to store post date and category/tag info etc in.
I also have a $pagetitle variable assigned to a title.php include file for each folder. So say I am on a "June 2018" archive page, the text in that file will be "June 2018". If I am on say a "Tutorials" category page, that will be the text in the title.php.
In the json file, I have:
{
"Arraysortdate": "YYYYMMDD",
"Month": "Month YYYY",
"Category": ["cat1", "cat2", "etc"]
}
I am ordering the array newest to oldest using krsort with Arraysortdate as key.
How do I filter the array using $pagetitle as input, finding if there is a match in $postinfo_str, and if there isn't, remove that folder from the array?
All I can seem to find regarding array sorting is where the info in the $pageinfo_str is basically the array and so by that, the $title is the input and the output is the matching text from the $postinfo_str, whereas I want the output to be the folders that only have the matching text in the $postinfo_str to what the input ($pagetitle) is.
Here is my code I have.. Keep in mind this is flat file, I do not want a database to achieve this. See comments if you want an explaination.
<?php
$BASE_PATH = '/path/to/public_html';
// initial array containing the dirs
$dirs = glob($BASE_PATH.'/testblog/*/posts/*', GLOB_ONLYDIR);
// new array with date as key
$dirinfo_arr = [];
foreach ($dirs as $cdir) {
// get current page title from file
$pagetitle = file_get_contents("includes/title.php");
// get date & post info from file
$dirinfo_str = file_get_contents("$cdir/includes/post-info.json");
$dirinfo = json_decode($dirinfo_str, TRUE);
// add current directory to the info array
$dirinfo['dir'] = $cdir;
// add current dir to new array where date is the key
$dirinfo_arr[$dirinfo['Arraysortdate']] = $dirinfo;
}
// now we sort the new array
krsort($dirinfo_arr);
foreach($dirinfo_arr as $key=>$dir) {
$dirpath = $dir['dir'];
$dirpath = str_replace('/path/to/public_html/', '', $dirpath);
?>
<!--HTML HERE SUCH AS--!>
TEXT <br>
<?php
};
?>
I have difficulties following your problem description. Your code example is slightly confusing. It appears to load the same global includes/title.php for each directory. Meaning, the value of $pagetitle should be the same every iteration. If this is intended, you should probably move that line right outside the loop. If the file contains actual php code, you should probably use
$pagetitle = include 'includes/title.php';
or something similar. If it doesn't, you should probably name it title.txt. If it is not one global file, you should probably add the path to the file_get_contents/include as well. (However, why wouldn't you just add the title in the json struct?)
I'm under the assumption that this happened by accident when trying to provide a minimal code example (?) ... In any case, my answer won't be the perfect answer, but it hopefully can be adapted once understood ;o)
If you only want elements in your array, that fulfill certain properties, you have essentially two choices:
don't put those element in (mostly your code)
foreach ($dirs as $cdir) {
// get current page title from file
$pagetitle = file_get_contents("includes/title.php");
// get date & post info from file
$dirinfo_str = file_get_contents("$cdir/includes/post-info.json");
$dirinfo = json_decode($dirinfo_str, TRUE);
// add current directory to the info array
$dirinfo['dir'] = $cdir;
// add current dir to new array where date is the key
// ------------ NEW --------------
$filtercat = 'cat1';
if(!in_array($filtercat, $dirinfo['Category'])) {
continue;
}
// -------------------------------
$dirinfo_arr[$dirinfo['Arraysortdate']] = $dirinfo;
array_filter the array afterwards, by providing a anonymous function
// ----- before cycling through $dirinfo_arr for output
$filtercat = 'cat1';
$filterfunc = function($dirinfo) use ($filtercat) {
return in_array($filtercat, $dirinfo['Category']));
}
$dirinfo_arr = array_filter($dirinfo_arr, $filterfunc);
you should read up about anonymous functions and how you provide local vars to them, to ease the pain. maybe your use case is bettersuited for array_reduce, which is similar, except you can determine the output of your "filter".
$new = array_filter($array, $func), is just a fancy way of writing:
$new = [];
foreach($array as $key => $value) {
if($func($value)) {
$new[$key] = $value;
}
}
update 1
in my code samples, you could replace in_array($filtercat, $dirinfo['Category']) with in_array($pagetitle, $dirinfo) - if you want to match on anything that's in the json-struct (base level) - or with ($pagetitle == $dirinfo['Month']) if you just want to match the month.
update 2
I understand, that you're probably just starting with php or even programming, so the concept of some "huge database" may be frightening. But tbh, the filesystem is - from a certain point of view - a database as well. However, it usually is quite slow in comparison, it also doesn't provide many features.
In the long run, I would strongly suggest using a database. If you don't like the idea of putting your data in "some database server", use sqlite. However, there is a learning curve involved, if you never had to deal with databases before. In the long run it will be time worth spending, because it simplifys so many things.

Detect Languages; CakePHP updateAll Bad Performance

UPDATE: I think the cakePhp updateAll is the problem. If i uncomment the updateAll and pr the results i get in 1-2 seconds so many language Detections like in 5 minutes!!!! I only must update one row and can determine that row with author and title... is there a better and faster way???
I'm using detectlanguage.com in order to detect all english texts in my sql database. My Database consists of about 500.000 rows. I tried many things to detect the lang of all my texts faster. Now it will take many days... :/
i only send 20% of the text (look at my code)
i tried to copy my function and run the function many times. the copied code shows the function for all texts with a title starting with A
I only can run 6 functions at the same time... (localhost)... i tried a 7th function in a new tab, but
Waiting for available socket....
public function detectLanguageA()
{
set_time_limit(0);
ini_set('max_execution_time', 0);
$mydatas = $this->datas;
$alldatas = $mydatas->find('all')->where(['SUBSTRING(datas.title,1,1) =' => 'A'])->where(['datas.lang =' => '']);
foreach ($alldatas as $row) {
$text = $row->text;
$textLength = round(strlen($text)*0.2);
$text = substr($text,0,$ltextLength);
$title = $row->title;
$author = $row->author;
$languageCode = DetectLanguage::simpleDetect($text);
$mydatas->updateAll(
['lang' => $languageCode], // fields
['author' => $author,'textTitle' => $title]); // conditions*/
}
}
I hope some one has a idea for my problem... Now the language detection for all my texts will take more than one week :/ :/
My computer runs over 20 hours with only little interruptions... But i only detected the language of about 13.000 texts... And in my database are 500.000 texts...
Now i tried sending texts by batch, but its also to slow... I always send 20 texts in one Array and i think thats the maximum...
Is it possible that the cakePhp 3.X updateAll-function makes it so slowly?
THE PROBLEM WAS THE CAKEPHP updateAll
Now i'm using: http://book.cakephp.org/3.0/en/orm/saving-data.html#updating-data with a for loop and all is fast and good
use Cake\ORM\TableRegistry;
$articlesTable = TableRegistry::get('Articles');
for ($i = 1; $i < 460000; $i++) {
$oneArticle = $articlesTable->get($i);
$languageCode = DetectLanguage::simpleDetect($oneArticle->lyrics);
$oneArticle->lang = $languageCode;
$articlesTable->save($oneSong);
}

Simple Dom HTML tags without attributes

Hello I am trying to pull back roster information from ESPN.com. Each team's roster is saved into a table. I am trying to figure a way to save each tag into a variable as appropriate however each tag does not have an ID such as "jersey_number"/"player_name" so search through this has given me some problems. Here is what I have so far - If you could give me a pointer or 2 that would be much appreciated.
<?php
require_once("../tools/simple_html_dom.php");
require_once("../tools/Utilities.php");
$url = "http://espn.go.com/nfl/team/roster/_/name/den/denver-broncos";
$espnHTML = file_get_html("http://espn.go.com/nfl/team/roster/_/name/den/denver-broncos");
foreach($espnHTML->find("table.tablehead",0)->find('tr[class^=odd]') as $rosterRow)
{
foreach($rosterRow->find("td") as $playerInfo)
{
echo $playerInfo->plaintext."<br>";
}
}
?>
How can I assign these td tags into appropriate variables without "ids"? Attached is a sample screenshot that may help you understand what I am talking about.
If the columns are in the same order for every player, using your $rosterrow->find("td") should return an indexed array that you can access using $playerrow[0..n].
Then, by analyzing what corresponds to what you can make a function like this:
$players = array();
foreach($espnHTML->find("table.tablehead",0)->find('tr[class^=odd]') as $rosterRow)
{
$playerRow = $rosterRow->find("td");
$name = $playerRow[0];
$jersey = $playerRow[1];
// more can be added, of course.
$players[$name] = array();
$players[$name]["jersey"] = $jersey;
// and others
}
For table
John Appleseed | 12
---------------|----
Richard Brooks | 34
this will result in an array like
{ "John Appleseed" => { "jersey" => 12 }, "Richard Brooks" => { "jersey" => 34}}
Please let me know if this helped.
If you're open to a different approach that may be more scalable/robust, then you may also want to take a look at Kimono Labs. You can use it to create structured API based on ESPN's data. I think you'd be able to define which part of the table held names, scores, etc. and would easily be able to call the API for the desired info.

PHP/MySQL - How to adjust query based on the length (characters) within database

I've had excellent support here, so I figured I'd try again, as I have no clue where to even begin looking for this answer.
I have a simple MySQL database, named "testimonials", which contains 3 tables, "id", "name", "content"
What I want to do, is display testimonials within a fixed size block. Just simply displaying the content is no problem at all, however where I'm stuck is the (somewhat) unique way I'm trying to make it work. I would like to display a random item on each page load, and then to check the character length of the "content" within the testimonial, and if it's equal to or greater than XX length, then just display the one testimonial, otherwise if it's less than XX in length to display a second testimonial (assuming it combined with the first doesn't break the container box).
The box in question is 362px in width and 353px in height using 14px font with Verdana. An example of how the testimonial will appear on the page is like this:
"This is the testimonial content, some nice message from a client."
-- Billy Bob, Owner, Crazy Joe's Tavern
The "name" table in the database holds everything in bold (minus the -- of course), in case someone felt the need to ask.
As I typed that, I felt as if I was asking for a miracle, however I'll still post the question, hoping someone might just know the answer. As always, thanks for any help I may get, if this is just simply asking too much, I'm not totally against the idea of only displaying one testimonial at a time making a ground rule saying they have to contain a minimum of XX characters.
Thanks!
Quick Update: I didn't expect to get answers so quickly, I'm not at my desk at the moment, so as soon as I sit back down I'll go through and see which answer fits best. However, do you guys get together and try to make your answer more complex than the previous answer? lol, thanks though, for anyone who's offering help, you guys rock!
Final edit: I decided against this whole idea, as it just way over complicated everything. For the time being, I'm just going to display all testimonials, and make them scroll, while I work on a jQuery snippet to make it prettier. Thanks everyone for your help though! Should I decide again to do this, I'll be trying my chosen answer.
You just need a loop. Pseudo-code:
$length = 0;
$target = 200; // or whatever
while( $length < $target ) {
$comment = getOneComment();
displayComment($comment);
$length += strlen( $comment['content'] ); // assuming getOneComment() returns an associative array
}
To make it pretty, if the display box is going to a be a fixed height, you could use some jQuery to toggle whether to show the second comment on not.
Assuming you have testimonials in an array:
$testimonials = array(
't1' => array(
'content' => 'testimonials 1 content..',
'author' => 'the author'
),
't2' => array(
'content' => 'testimonials 2 content..',
'author' => 'the author 2'
),
);
You could have an maxLengthTestimonialsContent and maxLenthAllTestimonnials variable :
$maxLengthTestimonialsContent = 120;
$maxLenthAllTestimonnials = 240;
And now with a simple loop you build the array testimonials that you will use to show:
$testimonialsToShow = array();
$i = 1; $totalLength = 0
foreach($testimonials as $t) {
if( $i > 1 && strlen( $t['content']) < $maxLengthTestimonialsContent
&& $totalLength < $maxLenthAllTestimonnials )
break; // basically here you test that testimonials less first
// and with less length than maxLengthTestimonial, and also
// total length less than maxLengthAll to be stored
//in $testimonialsToShow
else {
$testimonialsToShow[] = $t;
$totalLength = $t['content'];
}
}
Something like this is what you would need.
<?php
$str = $res["testimonial"];
if (strlen($str) > 50) {
// Logic to retrieve and display second testimonial
}
?>
Obviously there's some more processing you'll have to come up with to determine if the second testimonial is short enough to fit or not. But that should get you started.
EDIT:
For the randomization, I use this on my own site:
$referrals = mysql_query("SELECT id FROM ts_testimonials");
$referralView = array();
$i = 0;
while ($newReferral = mysql_fetch_array($referrals)) {
$referralView[$i] = $newReferral['id'];
$i++;
}
if (sizeof($referralView) >= 1){
$referralTop = rand(0,sizeof($referralView)-1);
$newReferralTop = mysql_fetch_array(mysql_query("SELECT * FROM ts_testimonials WHERE id = '".$referralView[$referralTop]."'"));
if (sizeof($referralView) >=2){
$referralBottom = rand(0,sizeof($referralView)-1);
while ($referralBottom == $referralTop) {
$referralBottom = rand(0,sizeof($referralView)-1);
}
$newReferralBottom = mysql_fetch_array(mysql_query("SELECT * FROM ts_testimonials WHERE id = '".$referralView[$referralBottom]."'"));
}
}

Adding an Array multiple times in the DB via Controller

I'm having an issue producing this array multiple times upon how many coupons purchased.
Now it looks like
$coupon_array = array(
'user_id'=>$_POST["user_id"],
'mergent_id'=>$_POST["merchant_id"],
'deals_id'=>$_POST["deal_id"],
'order_id'=>$order_id,
'secret'=>$secret,
'expire_time'=>$time,
'create_time'=>$time,
'status'=>1
);
$this->common_model->insertData('coupon', $coupon_array);
But i have a post value such as:
"quantity"=>$_POST["quantity"]
and i would like to produce this X times. Example:
$quantity x $this->common_model->insertData('coupon', $coupon_array);
Sorry for my english, and i hope i explain this so it's understandable... ;)
Another one! when we insert the coupons they all have the same md5($secret), is it possible to have that also with all the different code...
$secret = md5($secret);
$coupon_array = array(
'user_id'=>$_POST["user_id"],
'mergent_id'=>$_POST["merchant_id"],
'deals_id'=>$_POST["deal_id"],
'order_id'=>$order_id,
'secret'=>$secret,
'expire_time'=>$time,
'create_time'=>$time,
'status'=>1
);
Well, if I understand what you want, you can use for, but that's obvious:
for($i=0; $i<$this->input->post('quantity');$i++) {
$coupon_array['secret'] = md5($coupon_array['secret'].$i);
$this->common_model->insertData('coupon', $coupon_array);
}
Also, never use $_POST["..."] in CodeIgniter, use only $this->input->post('...') as it escapes properly. More info about input class can be found here.
for ($i=0; $i<$quanity; $i++) {
$this->common_model->insertData('coupon', $coupon_array);
}

Categories