Recursive parsing function - php

I made a function that parses a certain page of a website(a forum thread). It should select users and their posts and then go on to the next page and do the same. While it does that, its return value is always null. I think I made a mistake with the recursion, but can't really figure it out.
Here is the function, I made it return only the userlist, for now.
function getWinners( $thread,$userlist,$postlist ) {
//libxml_use_internal_errors(true);
$html = file_get_html( $thread );
//get users
$users=$html->find( 'li[class="postbitlegacy postbitim postcontainer old"] div[class=username_container] strong span' );
foreach ( $users as $user )
//echo $user . '<br>';
array_push( $userlist, $user );
//get posts
$posts=$html->find( 'li[class="postbitlegacy postbitim postcontainer old"] div[class=postbody] div[class=content]' );
foreach ( $posts as $post )
// echo $post . '<br>';
array_push( $postlist, $post );
//check if there is a next page
if ( $next=$html->find( 'span[class=prev_next] a[rel="next"]', 0 ) ) {
$testa='http://forums.heroesofnewerth.com/'.$next->href;
// echo $testa. '<br>';
$html->clear();
unset( $html );
//recursive calls until the last page of the forum thread
getWinners( $testa,$userlist,$postlist );
//no more thread, return users
}else return $userlist;
}
And the call
$thread='http://forums.heroesofnewerth.com/showthread.php?553261';
$userlist=array();
$postlist=array();
$stuff=getWinners( $thread,$userlist,$postlist);
echo $stuff[0];
Here, stuff is empty.

At the very least you would need to use the value returned from the recursive function:
getWinners( $testa,$userlist,$postlist );
should be:
return getWinners( $testa,$userlist,$postlist );
// or, more likely:
return array_merge($users, getWinners($testa,$userlist,$postlist));
Apart from that I'm not sure if you are returning the right information, probably (you'd need to check...) you need something like:
//cursive calls until the last page of the forum thread
return array_merge($userlist, getWinners($testa,$userlist,$postlist));
}
else {
//no more thread, return users
return $userlist;
}

Related

How to improve/shorten PHP code syntax? Wordpress example

I have used browserstack many times for idea's and bugs. I'm at an ok level now but I like to hone my skills.
The following code is a custom piece of coding I have done to a template. It works perfectly. How can I improve this code? It seems way to long for what I'm trying to achieve. How can I shorten this code?
// Display treatments specialism icons that a location is practising
// Fetch all the entries from WP database
function get_specs($location_id) {
//Register globals
global $wpdb;
// The query
$sql = "SELECT * FROM $wpdb->postmeta";
// Get the results array from the query
$results = $wpdb->get_results($sql) or die(mysql_error());
// Assign the results array and iterate 1 by one
foreach( $results as $results ) {
$meta_key = $results->meta_key;
// Every time the key value is a 'naam' (name) check wether this is the name of a specialism.
// The names are not gotten by certain id's because or flexibility (Client add more/change spacialisms later without programming intervention)
if ($meta_key == "naam") {
// The name value to be compared
$specialismen_naam = $results->meta_value;
// Store the ID connected to the found naam for later use
$specialismen_id = $results->post_id;
// Fetch the specialism meta_value array of all the locations, all specialisms practised are in 1 array
$specialismen = get_post_meta($location_id, 'specialiteiten', true);
// Search location specialism array and compare it with the name value. if it has a match continue
if (in_array($specialismen_naam, $specialismen)) {
// Get the specialism image from the earlyer stored id
$thumbnail_image = get_post_meta( $specialismen_id, 'thumbnail_image', true );
// Get the link to the specialism page for if clicked
$link = get_page_link(get_post_meta( $specialismen_id, 'link', true ));
//display the specialism icon with link to specialism page
echo '<li>'. wp_get_attachment_image( $thumbnail_image, array(30,30) ) .'</li>';
}
}
}
}
// Get the Locations
// Fetch the data
function get_location_fp($object_ids) {
// register globals
global $wpdb;
// Query
$sql = "SELECT * FROM $wpdb->postmeta WHERE post_id = $object_ids";
// Results
$results = $wpdb->get_results($sql) or die(mysql_error());
foreach( $results as $results ) {
$meta_key = $results->meta_key;
$meta_value = $results->meta_value;
// If there is a location thumbnail assigned (has to be), process
if ($meta_key == "lokatie_thumbnail") {
// fetch displayed data from event in variable. Telephone, address, name, link to location page
$telefoonnummer = get_post_meta( $object_ids, 'telefoonnummer', true );
$adres = get_post_meta( $object_ids, 'adres', true );
$naam = get_post_meta( $object_ids, 'naam', true );
$link = get_page_link(get_post_meta( $object_ids, 'link', true ));
// Fetch thumbnail image of each location
$thumbnail_image = get_post_meta( $object_ids, 'lokatie_thumbnail', true );
// Display the location
echo '<div id="lokatie-fp"><div class="lokatie-image">'. wp_get_attachment_image( $thumbnail_image ) .'</div><div class="lokatie-gegevens"><h3>'. $naam .'</h3><p>'. $telefoonnummer .'</p><p>'. $adres .'</p>';
// Add all specialisms that are practised at this location
echo '<ul>'. get_specs($object_ids) .'</ul></div></div></a>';
}
}
}
// Called somewhere in template:
<?php get_location_fp(62); ?>
<?php get_location_fp(67); ?>
<?php get_location_fp(105); ?>
<?php get_location_fp(104); ?>
Indenting your code consistently will make it much easier to read/debug
// Display treatments specialism icons that a location is practising
// Fetch all the entries from WP database
function get_specs($location_id) {
//Register globals
global $wpdb;
// The query
$sql = "SELECT * FROM $wpdb->postmeta";
// Get the results array from the query
$results = $wpdb->get_results($sql) or die(mysql_error());
// Assign the results array and iterate 1 by one
foreach( $results as $results ) {
$meta_key = $results->meta_key;
// Every time the key value is a 'naam' (name) check wether this is the name of a specialism.
// The names are not gotten by certain id's because or flexibility (Client add more/change spacialisms later without programming intervention)
if ($meta_key == "naam") {
// The name value to be compared
$specialismen_naam = $results->meta_value;
// Store the ID connected to the found naam for later use
$specialismen_id = $results->post_id;
// Fetch the specialism meta_value array of all the locations, all specialisms practised are in 1 array
$specialismen = get_post_meta($location_id, 'specialiteiten', true);
// Search location specialism array and compare it with the name value. if it has a match continue
if (in_array($specialismen_naam, $specialismen)) {
// Get the specialism image from the earlyer stored id
$thumbnail_image = get_post_meta( $specialismen_id, 'thumbnail_image', true );
// Get the link to the specialism page for if clicked
$link = get_page_link(get_post_meta( $specialismen_id, 'link', true ));
//display the specialism icon with link to specialism page
echo '<li>'. wp_get_attachment_image( $thumbnail_image, array(30,30) ) .'</li>';
}
}
}
}
// Get the Locations
// Fetch the data
function get_location_fp($object_ids) {
// register globals
global $wpdb;
// Query
$sql = "SELECT * FROM $wpdb->postmeta WHERE post_id = $object_ids";
// Results
$results = $wpdb->get_results($sql) or die(mysql_error());
foreach( $results as $results ) {
$meta_key = $results->meta_key;
$meta_value = $results->meta_value;
// If there is a location thumbnail assigned (has to be), process
if ($meta_key == "lokatie_thumbnail") {
// fetch displayed data from event in variable. Telephone, address, name, link to location page
$telefoonnummer = get_post_meta( $object_ids, 'telefoonnummer', true );
$adres = get_post_meta( $object_ids, 'adres', true );
$naam = get_post_meta( $object_ids, 'naam', true );
$link = get_page_link(get_post_meta( $object_ids, 'link', true ));
// Fetch thumbnail image of each location
$thumbnail_image = get_post_meta( $object_ids, 'lokatie_thumbnail', true );
// Display the location
echo '<div id="lokatie-fp"><div class="lokatie-image">'. wp_get_attachment_image( $thumbnail_image ) .'</div><div class="lokatie-gegevens"><h3>'. $naam .'</h3><p>'. $telefoonnummer .'</p><p>'. $adres .'</p>';
// Add all specialisms that are practised at this location
echo '<ul>'. get_specs($object_ids) .'</ul></div></div></a>';
}
}
// Called somewhere in template:
<?php get_location_fp(62); ?>
<?php get_location_fp(67); ?>
<?php get_location_fp(105); ?>
<?php get_location_fp(104); ?>
Sometimes it can be easier to read if you can avoid doing nested if statements, for example:
if ($meta_key != "naam") {
continue;
}
directly echoing out can sometimes be a bit confusing and can lead to output being sent when not desired (say if an error occurs). I quite like to build up an array of the output before rendering that:
$output = array();
$output[] = '<li>'. wp_get_attachment_image( $thumbnail_image, array(30,30) ) .'</li>';
...
...
echo implode(PHP_EOL,$output);
Other than those minor things I'd say its fine. It's really nice and verbose, easy to read, well documented.
As for Jalpa's comments I'd say that its good practice to have the SQL query and the execution of it on different lines, it improves readability. And there's no need for an if condition before the foreach, that takes care of itself.
Edit
You mentioned your li's are being rendered early. From your function get_specs() you certainly don't want to render anything but here you can return your output to the get_location_fp() calling function.
function get_specs($loctation_id) {
...
$output = array();
...
$output[] = '<li>'. wp_get_attachment_image( $thumbnail_image, array(30,30) ) .'</li>';
...
return implode(PHP_EOL,$output);
}
function get_location_fp($object_ids) {
...
$output[] = '<ul>'. get_specs($object_ids) .'</ul></div></div></a>';
...
}
By returning the output from get_specs() rather than rendering it, it will be inserted between the uls and not before it.
I think you need to add below changes :
1) Please write query like this $wpdb->get_results("SELECT * FROM $wpdb->postmeta") no need to write in two lines.
2) please put if condition before foreach is not empty or count() array > 0.

php foreach multiple array timeout

There are two functions, one is init function to get some information from database and then transfer the account info to another function get the data from remote website, then test_function_save_data() get the correct data and check & insert them into the database.
Question is: if use the print_r($post) in test_function_save_data(), the function can work normally. but remove this print_r or replace it with sleep(), all of the data can be checked and inserted into dabase, but the current page is not redirected and blank page will be display.
so, where is wrong? how to solve it?
<?php
function test_function_get_account_init() {
if(test_function_get_sns_account('blog')) {
$b = 0;
foreach (test_function_get_sns_account('blog') as $team_id => $blog_account_name) {
$blog = test_theme_get_blog($team_id, $blog_account_name);
if($blog && is_array($blog['posts'])){
$b += test_function_save_data($blog['posts']);
}
}
echo '<h5successfuly!</h5>';
} else {
echo 'not found.';
}
}
function test_function_save_data($post_data) {
set_time_limit(720);
global $wpdb;
$i = 0;
foreach ($post_data as $post) {
// echo '<div style="display:none;">';
// print_r($post);
// echo '</div>';
if(test_function_check_post_unquine($post['social_origin_id']) && isset($post['social_origin_id'])) {
$social_post_data = array(
'post_title' => $post['post_title'],
'post_content' => $post['post_content'],
'post_status' => 'publish',
'post_author' => get_current_user_id(),
'post_type' => 'social_post'
);
$latest_post_id = wp_insert_post( $social_post_data );
if($post['social_origin_url']) {
add_post_meta($latest_post_id, 'social_origin_url', $post['social_origin_url']);
}
if($post['social_origin_id']) {
add_post_meta($latest_post_id, 'social_origin_id', $post['social_origin_id']);
}
if($post['user']) {
add_post_meta($latest_post_id, 'social_origin_user', $post['user']);
}
if($post['user']['team_account']) {
add_post_meta($latest_post_id, $post['user']['site_name'].'_social_user_id', $post['user']['team_account']);
}
if($post['media']) {
add_post_meta($latest_post_id, 'social_origin_thumbnail', $post['media']['url']);
}
$i++;
}
flush();
}
return $i;
}
This looks like a wordpress code? Have you tested print_r a single $post? In some frameworks, most of the objects are instance of a very complicated class. For ex. In laravel if you try to print_r a single model object it will result in a huge amount of data, so doing it in a loop can cause the timeout. Usually there is a way to get only the object's attributes. Hopefully this helps, maybe this should be in comment but my rep isn't enough for that

Recursive function for comment and reply PHP application

I am having difficulty conceptualizing a recursive function for appending replies to comments, replies to replies, replies to replies to replies, etc.
This is my comments table:
Which SHOULD look something like this when rendered:
As it stands I can render each comment associated with the article_id (excluding those that are NOT NULL, of course):
$comments = $commentClass->fetch_article_comments($article_id);
foreach($comments as $comment) {
$comment_id = $comment['comment_id'];
$member_id = $comment['member_id'];
$comment_text = $comment['comment_text'];
$comment_timestamp = timeAgo($comment['comment_timestamp']); //get time ago
//render comment using above variables
}
Now I'm assuming I need to add a recursive function at the end of the above foreach statement, but I have yet to come up with anything remotely successful in appending the comments replies and the replies to each reply.
Can anyone help me accomplish this or perhaps point me in the right direction. I am not entirely familiar with recursive functions. I have done some scanning of the internet and on stackoverflow looking for something that helps, but haven't found anything helpful yet.
I did come across this post which recommended using a hierarchical database system, but I think I would prefer to use a php recursive function for this.
Thanks.
edit
By using the below answers I am only returning the results first comment and then it iterates and displays that one comment indefinitely. I can't figure out why?
My php:
function display_comments($article_id, $parent_id=0, $level=0) {
global $comment;
global $member;
global $signed_in;
global $username;
$comments = $comment->fetch_article_comments($article_id, $parent_id);
foreach($comments as $data) {
$comment_id = $data['comment_id'];
$c_member_id = $data['member_id'];
$comment_text = $data['comment_text'];
$comment_timestamp = timeAgo($data['comment_timestamp']); //get time ago
$member_data = $member->fetch_member_data($c_member_id);
$c_member_username = $member_data['member_username'];
$c_member_avatar = $member_data['member_avatar'];
//render HTML here
$parent = $data['comment_parent'];
display_comments($article_id, $parent, $level+1);
}//end foreach
}//end display_comments()
and my PDO query:
public function fetch_article_comments($article_id, $parent_id) { //$page = (int)(!isset($_GET['page'])) ? 0 : $_GET['page'];
if ($parent_id > 0) {
$parent_id = "= $parent_id";
} else {
$parent_id = "IS NULL";
}
$query = $this->db->prepare("SELECT * FROM `comments2` WHERE `article_id` = $article_id AND `comment_parent` $parent_id ORDER BY `comment_timestamp` DESC");
try{
$query->execute();
$comments = $query->fetchAll(); //returns an array
$query->closeCursor();
return $comments;
} catch(PDOException $e){
die($e->getMessage());
}
}
The core of the problem is this:
$comments = $commentClass->fetch_article_comments($article_id);
I assume, this function somwhere creates and runs SQL, that is similar to SELECT ... WHERE comments.article_id=$article_id. This is not sufficient - you need something like
$comments = $commentClass->fetch_article_comments($article_id, $parent_id);
that translates into SQL similar to SELECT ... WHERE comments.article_id=$article_id AND comments.comment_parent ($parent_id>0)?"=$parent_id":"IS NULL"
Now you can write your PHP function:
function display_comments ($article_id, $parent_id=0, $level=0) {
$comments = $commentClass->fetch_article_comments($article_id, $parent_id);
foreach($comments as $comment) {
$comment_id = $comment['comment_id'];
$member_id = $comment['member_id'];
$comment_text = $comment['comment_text'];
$comment_timestamp = timeAgo($comment['comment_timestamp']); //get time ago
//render comment using above variables
//Use $level to render the intendation level
//Recurse
display_comments ($article_id, $comment_id, $level+1);
}
}
And finally call it with display_comments ($article_id);
You could do something like:
function getCommentsForParent($parent="") {
echo "<div class=\"comment\">";
$db = get("select your db logics where parent = $parent");
foreach ($db as $comment) {
echo "print your comment in a box and make a div around the hole comments"
getCommentsForParent($comment['parent_id']);
}
echo "</div>";
}
invoke function with getCommentsForParent()
With your code it should be something like:
function getCommentForParent($parent="") {
global $commentsClass, $article_id;
$comments = $commentClass->fetch_article_comments($article_id,$parent);
foreach($comments as $comment) {
$comment_id = $comment['comment_id'];
$member_id = $comment['member_id'];
$comment_text = $comment['comment_text'];
$comment_timestamp = timeAgo($comment['comment_timestamp']); //get time ago
getCommentForParent($comment['parent']);
}
}
Look closely, ive adjusted your fetch article_comments. It now has a listener for $parent. Make sure that when your $parent = "", the class will only select the comments with empty parent.
invoke with getCommentsForParent()
It will automatically loop through the parent. Ofcourse this is highly conceptual but given your code you should get the hang of it.

Inserting multiple checkbox values in mysql

i have a joomla component for making appointments and i have checkboxes for starting dates of the appointments...my problem is that i can only make one appointment at a time,i want to be able to check multiple boxes so the values for those boxes can be saved in mysql,when i check multiple checkboxes only the last checked is saved in database...
here is the code from joomla component that i think that has to be adjusted so help guys if you can...
this is the code for checkbox...
$timetableHTML .= '<td class="timeSlot timeFree" ><input type="checkbox" name="appointment[]" value="'.$startKey.'" onclick="changeTimes(\''.$calendar->min_duration.'\',\''.$startKey.'\',\''.$endKey.'\')"/></td>';
and this is the save function in controller of the component...
function save() {
global $app;
JRequest::checkToken() or jexit( 'Invalid Token' );
$db =& JFactory::getDBO();
$row =& JTable::getInstance('appointments', 'Table');
$post = JRequest::get( 'post',4 );
if (!$row->bind( $post )) { JError::raiseError(500, $row->getError() ); }
for ($i=1;$i<=10;$i++) {
if (is_array($row->{'field'.$i})) $row->{'field'.$i} = implode('|',$row->{'field'.$i}); $row->{'field'.$i} = strip_tags($row->{'field'.$i});
}
if (!$row->check()) { JError::raiseError(500, $row->getError() ); }
if (!$row->store()) { JError::raiseError(500, $row->getError() ); }
$row->checkin();
if ($this->config->emails){
$this->notifyOwner(array($row->id));
$this->notifyAppointee(array($row->id));
}
$url = JRoute::_('index.php?option=com_jxtcappbook'.(JRequest::getInt( 'pop', 0) ? '&view=complete&tmpl=component' : ''));
$this->setRedirect($url ,JText::_( 'Termin je zakazan!'.$pop ));
}
i googled a bit and i think i need to set jrequest::get with array,am i right?
Assuming Joomla >1.6. Since you use JRequest a fair amount:
$appointments = JRequest::getVar('appointments', null, 'post', 'array');
or better yet since this will be deprecated post 3.0 you can use JInput:
$jinput = JFactory::getApplication()->input;
$appointments = $jinput->post->get('appointments', 'null', 'ARRAY');
Sanitize input and add to DB:
foreach (array_keys($appointments ) as $element) {
$myappointments[] = $db->quote($element);
}
// construct query using implode and use comma separator
$myappointments = implode(',', $myappointments );
$db =& JFactory::getDBO();
$query = $db->getQuery(true);
$query = sprintf('UPDATE $db->quoteName(#__mytable) SET $db->quote(...) WHERE $db->quote(...) IN (%s)', $myappointments );
$db->setQuery($query);
$db->query();
You get the idea...
EDIT (based on your comment):
I still don't know what you are trying to achieve. So it is hard for me to provide direction. I'll take another stab at it. I'm guessing you want to take the values that are checked from the form and put that into the database.
//this pulls out the values in an array of all the things that have been "checked" (selected in the checkbox)
$jinput = JFactory::getApplication()->input;
$appointments = $jinput->post->get('appointments', 'null', 'ARRAY');
//**This is not code you need** I just want to illustrate what you are getting.
//This is looping through the values of the checkboxes to see what you have
for($i=0; $i < count($appointments); $i++){
echo "Selected " . $appointments[$i];
}
The code I provided before shows you how to take the values and store into a DB. I can't give instructions on the DB because I don't know the DB structure.

How do I find out how many edits a user has for my MediaWiki extension?

I'm writing an extension that will allow me to add the magic words: CURRENTUSER, CURRENTUSERREALNAME, CURRENTUSERLANGABBR, CURRENTUSERGROUPS, and now I want to add CURRENTUSEREDITCOUNT and CURRENTUSEREDITCOUNTALL.
That section of my code is currently:
function wfGetCustomVariable(&$parser,&$cache,&$index,&$ret) {
switch ($index) {
case MAG_CURRENTUSER:
$parser->disableCache(); # Mark this content as uncacheable
$ret = $GLOBALS['wgUser']->getName();
break;
case MAG_CURRENTUSERREALNAME:
$parser->disableCache(); # Mark this content as uncacheable
$ret = $GLOBALS['wgUser']->getRealName();
break;
case MAG_CURRENTUSERLANGABBR
$parser->disableCache(); # Mark this content as uncacheable
$ret = $GLOBALS['wgLang']->getCode();
break;
case MAG_CURRENTUSERGROUPS
$parser->disableCache(); # Mark this content as uncacheable
$array = $GLOBALS['wgUser']->getEffectiveGroups();
$ret = implode(",", $array);
break;
}
return true;
}
However, I can't seem to find the $GLOBAL for the edit counts. I've done some research based on other extensions that use different edit counts for different reasons and have found:
For CURRENTUSEREDITCOUNT:
function wfContributionseditcount( $uid ) {
if ( $uid != 0 ) {
global $wgOut, $wgLang;
$wgOut->addWikiText( wfMsgExt( 'contributionseditcount', array( 'parsemag' ),
$wgLang->formatNum( User::edits( $uid ) ),
User::whoIs( $uid ) ) );
}
return true;
}
and for CURRENTUSEREDITCOUNTALL:
public function execute( $params ) {
global $wgOut, $wgUser;
$skin = $wgUser->getSkin();
$this->setHeaders();
$this->loadRequest( $params );
$wgOut->addHTML( $this->makeForm() );
if( $this->target ) {
if( User::isIP( $this->target ) ) {
$this->showResults( $this->countEditsReal( 0, $this->target ) );
} else {
$id = User::idFromName( $this->target );
if( $id ) {
$this->showResults( $this->countEditsReal( $id, false ), $id );
} else {
$wgOut->addHTML( '<p>' . wfMsgHtml( 'countedits-nosuchuser', htmlspecialchars( $this->target ) ) . '</p>' );
}
}
}
$this->showTopTen( $wgOut );
return true;
}
I have tried to learn PHP on my own in the past, and have struggled with it. I'm signed up for a PHP class at my local community college, but I do not start until Fall `12. Am I looking in the right place, or is there a simpler place to find the user's edit counts? Maybe as part of /trunk/phase3/includes/User.php someplace? I should mention this needs to run on a wiki running MW 1.17.1, so classUser would not work where-as it is MW 1.18+.
If what you want is to change the definition of edit count, perhaps you should directly change the code where it reduces the user's editcount after a page is deleted.

Categories