Using a Loop Inside a Function - php

I'm still learning functions and how they work. I know what I'm doing wrong just not how to fix it. I am writing a function to pull image data out of a database and return it onto the screen. It works but if there is more than one image it will return the last image only. I know the problem is that $project_image is only returning the last image because of the way the while loop works but my question is how can i either not use a while loop or make it add more than one image to the $project_image variable.
Abridged Function
function get_project_image($id,$type="thumb",$src="false",$limit=1){
if($type =="main"){
$project_image_qry = mysql_query(" SELECT i_name FROM `project_images` WHERE i_project_id = '$id' AND i_type= '2' LIMIT $limit " ) or die(mysql_error());
$project_image="";
while($project_image_row = mysql_fetch_array($project_image_qry)) {
$project_image_result = mysql_fetch_array ($project_image_qry);
if($src=="true"){
$project_image .= '<img src="'.admin_settings('site_url').admin_settings('image_main_dir').'/'.$project_image_result['i_name'].'" alt="project_image"/>';
}
else{
$project_image .= $project_image_result['i_name'];
}
}
}
return $project_image;
}

Your while condition is fine, but you seem to be fetching twice, in $project_image_row and $project_image_result, so you're going to be skipping every other image. Just fetch the array once (in the while loop is good), and use $project_image_result instead of $project_image_row within the loop to refer to that array:
while($project_image_result = mysql_fetch_array($project_image_qry)) {
if($src=="true"){
$project_image .= '<img src="'.admin_settings('site_url').admin_settings('image_main_dir').'/'.$project_image_result['i_name'].'" alt="project_image"/>';
}
else{
$project_image .= $project_image_result['i_name'];
}
}
Also, it seems like by default you told it to only request one image from the database. You have a default parameter $limit=1, and you use an SQL LIMIT to filter the results, so unless you pass a fourth argument to get_project_image the mysql_query is only going to return one result (you didn't include the call to get_project_image, so I'm not sure if you handled that or not

Related

Always get an empty array in foreach loop

There are two columns in the database table "system". I have the systemId and want to get the mobileSystemId. But the variable $mobileSystemIds which I already defined as global is always empty.
EDIT: Now array_map doesn´t work. I always get my Exception output "Arrayfehler ArrayMap"
I have the following code :
$mobileSystemIds=array();
function getMobileSystemId($systemId)
{
global $mysqli;
global $mobileSystemIds;
$query="SELECT mobileSystemId FROM system WHERE systemId ='" .$systemId ."'";
if(!$result=$mysqli->query($query))
{
echo "Datenbankfehler DB-QUery";
exit(0);
}
if (!$mobileSystemId=$result->fetch_assoc())
{
echo "Datenbankfehler DB-Fetch";
exit(0);
}
$mobileSystemId=$mobileSystemId["mobileSystemId"];
echo "mobile System ID: " .$mobileSystemId ."<br />";
return $mobileSystemId;
}
if(!$mobileSystemIds=array_map("getMobileSystemId",$systemList))
{
echo "Arrayfehler ArrayMap";
}
In this case, using a return in your function would be much cleaner.
Nothing to do with your problem, but is your $systemId var trusted ? (To prevent SQL injection).
Update:
if(!$mobileSystemIds=array_map("getMobileSystemId",$systemList))
{
echo "Arrayfehler ArrayMap";
}
ought to read (just checked; it works for me):
$mobileSystemIds = array_map('getMobileSystemId', $systemsList);
if (empty($mobileSystemIds))
{
if (empty($systemsList) || !(is_array($systemsList)))
echo "OK: no mobile IDs, but no systems either";
else
echo "THIS now is strange :-(";
}
else
{
echo "Alles OK";
var_dump($mobileSystemIds);
}
I tried this by returning a dummy value based on input; if it does not work for you, there must be something strange in the database.
(Update: the text below refers to your original code, which did not use array mapping)
Your code ought to be working as it is. You put several $mobileSystemId 's into a single $mobileSystemId.
It works: I tested with a simpler code, removing the DB calls but leaving your code, and spelling, untouched.
So, the error must be elsewhere. I would guess that this code is included into something else, and:
the $mobileSystemIds = array(); declaration gets executed more than once, thereby losing all its data;
the $mobileSystemIds = array(); declaration is itself included in a more local scope and you read it from outside, reading an empty value or a totally different value.
Try replacing the first part of your code with:
GLOBAL $mobileSystemsIds;
if (defined($mobileSystemsIds))
trigger_error("mobileSystemsId defined more than once", E_USER_ERROR);
else
$mobileSystemsIds = array();
and also, in the function body:
if (!defined($mobileSystemsId))
trigger_error("mobileSystemsId should have been defined", E_USER_ERROR);

simple php foreach loop help needed

I have a for each loop like this
$sn_count = 1;
$prodfilter = "";
foreach($prods as $prod){
$prodfilter .= "<div class=\"product\">".$prod['product'][1]."</div>";
$sn_count++;
}
echo $prodfilter;
Now my problem my "product" class displaying border even if the $prod['product'][1] not available. So i would like to test it using if statement.
If (product value available) {
$prodfilter .= "<div class=\"product\">".$prod['product'][1]."</div>";
}
I tried like this.
if(!empty($prod['product'][1])) {
$prodfilter .= "<div class=\"product\">".$prod['product'][1]."</div>";
}
But its not working.
you can try couple of things
try this for a start
if(strlen(trim($prod['product'][$sn_count]))>0) {
$prodfilter .= "<div class=\"product\">".$prod['product'][$sn_count]."</div>";
}
or
if(isset($prod['product'][$sn_count])) {
$prodfilter .= "<div class=\"product\">".$prod['product'][$sn_count]."</div>";
}
The right thing in my opinion would be to check how many rows returned. I'll assume you are using MySQL since you did not specify. Please ask for additional help if you are not using it.
http://www.php.net/manual/en/function.mysql-num-rows.php
if (mysql_num_rows($prods)!=0) {
//Do your code
}
This should check if your query returned more than 0 rows (so it needs to be drawn). Does it fix it?
The right thing to do is to check if it's empty as you tried, but since it fails there obviously is some data there. You could do a var_dump and figure out what and why it is there which probably leads you to the source of the problem.
If by available you mean declared then isset is the right function to use by the way.

PHP mysql check inside a function

I have a function (which I did not write) inside an existing php tag in the head of a page that I've been using for several years the parses URL's and email addresses to make them clickable links:
function ParseURLs($str){
if(isset($str)){
$Output=strip_tags($str);
$Output=preg_replace("/(\swww\.)|(^www\.)/i"," http://www.",$Output);
$Output=preg_replace("/\b(((ftp|http(s?)):\/\/))+([\w.\/&=?\-~%;]+)\b/i"
,"<a href='$1$5' target='_blank' rel='nofollow'>$1$5</a>",$Output);
$Output=preg_replace("/\b([\w.]+)(#)([\w.]+)\b/i"
, "<a href='mailto:$1#$3'>$1#$3</a>",$Output);
return nl2br($Output);
}
}
I wanted to replace the rel='nofollow' with a php check of a MySQL dbase field and have it only put up the rel='nofollow' if the dbase field is empty. I tried to do it by replacing rel='nofollow' in the function with something like this which was my starting point:
<?php if (empty( $row_rswhatever['linkfollow'])) {echo "rel='nofollow'";}?>
or just this:
if (empty( $row_rswhatever['linkfollow'])) {echo "rel='nofollow'";}
I've tried it a hundred different ways (something good usually happens sooner or later) but cannot get it to work. I know from past experience that I am probably missing the boat on more than one issue, and would appreciate any help or guidance. Thanks.
A easy/lazy way to do it would be to continue doing it as you are doing now, however after the last $output=preg_replace add your if test and if you don't want the rel='nofollow', just use str_replace to remove it.
ie.
function ParseURLs($str)
{
if(isset($str)){
$Output=strip_tags($str);
$Output=preg_replace("/(\swww\.)|(^www\.)/i"," http://www.",$Output);
$Output=preg_replace("/\b(((ftp|http(s?)):\/\/))+([\w.\/&=?\-~%;]+)\b/i","<a href='$1$5' target='_blank' rel='nofollow'>$1$5</a>",$Output);
$Output=preg_replace("/\b([\w.]+)(#)([\w.]+)\b/i", "<a href='mailto:$1#$3'>$1#$3</a>",$Output);
if (empty( $row_rswhatever['linkfollow'])) {
$Output = str_replace(" rel='nofollow'", "", $Output);
}
return nl2br($Output);
}
}
Without knowing exactly what you'd be checking for in the database:
function ParseUrls($str) {
$sql = "SELECT ... FROM yourtable WHERE somefield='" . mysql_real_escape_string($str) ."'";
$result = mysql_query($sql) or die(mysql_error());
$rel = (mysql_num_rows($result) == 0) ? ' rel="nowfollow"' : '';
blah blah blah
}
Incidentally, the isset check is useless in your code. The function parameter does not have a default value (function x($y = default)), so if no parameter is specified in the calling code, it will cause a fatal error in PHP anyways.
This also assumes that you've already connected to MySQL elsewhere in your code, and are using the mysql library (not mysqli or pdo or db or whatever else).

PHP, XML, Accessing Attributes

I'm having a some trouble accessing attributes in my XML. My code is below. Initially I had two loops and this was working with no problems.
I would first get the image names and then use the second loop to get the story heading and story details. Then insert everything into the database. I want to tidy up the code and use only one loop. My image name is store in the Href attribute. ()
Sample XML layout (http://pastie.org/1850682). The XML layout is a bit messy so that was the reason for using two loops.
$xml = new SimpleXMLElement('entertainment/Showbiz.xml', null, true);
// Get story images
//$i=0;
//$image = $xml->xpath('NewsItem/NewsComponent/NewsComponent/NewsComponent/NewsComponent/NewsComponent/ContentItem');
// foreach($image as $imageNode){
// $attributeArray = $imageNode->attributes();
// if ($attributeArray != ""){
// $imageArray[$i] = $attributeArray;
// $i++;
// }
//}
// Get story header & detail
$i=0;
$story = $xml->xpath('NewsItem/NewsComponent/NewsComponent/NewsComponent');
foreach($story as $contentItem){
//$dbImage = $imageArray[$i]['Href'];
foreach($contentItem->xpath('ContentItem/DataContent/nitf/body/body.head/hedline/hl1') as $headline){
$strDetail = "";
foreach($contentItem->xpath('ContentItem/DataContent/nitf/body/body.content/p') as $detail){
$strDetail .= '<p>'.$detail.'</p>';
foreach($contentItem->xpath('NewsComponent/NewsComponent/ContentItem') as $imageNode){
$dbImage = $imageNode->attributes();
}
}
$link = getUnique($headline);
$sql = "INSERT INTO tablename (headline, detail, image, link) VALUES ('".mysql_real_escape_string($headline)."', '".mysql_real_escape_string($strDetail)."', '".mysql_real_escape_string($dbImage)."', '".$link."')";
if (mysql_query($sql, $db) or die(mysql_error())){
echo "Loaded ";
}else{
echo "Not Loaded ";
}
}
$i++;
}
I think I'm close to getting it. I tried putting a few echo statements in the fourth nested foreach loop, but nothing was out. So its not executing that loop. I've been at this for a few hours and googled as well, just can't manage to get it.
If all else fails, I'll just go back to using two loops.
Regards,
Stephen
This was pretty difficult to follow. I've simplified the structure so we can see the parts of the hierarchy we care about.
It appears that the NewsComponent that has a Duid attribute is what defines/contains one complete news piece. Of its two children, the first child NewsComponent contains the summary and text, while the second child NewsComponent contains the image.
Your initial XPath query is for 'NewsItem/NewsComponent/NewsComponent/NewsComponent', which is the first NewsComponent child (the one with the body text). You can't find the image from that point because the image isn't within that NewsComponent; you've gone one level too deep. (I was tipped off by the fact I got a PHP Notice: Undefined variable: dbImage.) Thus, drop your initial XPath query back a level, and add that extra level to your subsequent XPath queries where needed.
From this:
$story = $xml->xpath('NewsItem/NewsComponent/NewsComponent/NewsComponent');
foreach($story as $contentItem){
foreach($contentItem->xpath('ContentItem/DataContent/nitf/body/body.head/hedline/hl1') as $headline){
foreach($contentItem->xpath('ContentItem/DataContent/nitf/body/body.content/p') as $detail){
foreach($contentItem->xpath('NewsComponent/NewsComponent/ContentItem') as $imageNode){ /* ... */ }}}}
to this:
$story = $xml->xpath('NewsItem/NewsComponent/NewsComponent');
foreach($story as $contentItem){
foreach($contentItem->xpath('NewsComponent/ContentItem/DataContent/nitf/body/body.head/hedline/hl1') as $headline){
foreach($contentItem->xpath('NewsComponent/ContentItem/DataContent/nitf/body/body.content/p') as $detail){
foreach($contentItem->xpath('NewsComponent/NewsComponent/NewsComponent/ContentItem') as $imageNode){ /* ... */ }}}}
However, the image still doesn't work after that. Because you're using loops (sometimes unnecessarily), $dbImage gets reassigned to an empty string. The first ContentItem has the Href attribute, which gets assigned to $dbImage. But then it loops to the next ContentItem, which has no attributes and therefore overwrites $dbImage with an empty value. I'd recommend modifying that XPath query to find only ContentItems that have an Href attribute, like this:
->xpath('NewsComponent/NewsComponent/NewsComponent/ContentItem[#Href]')
That should do it.
Other thoughts
Refactor to clean up this code, if/where possible.
As I mentioned, sometimes you are looping and nesting when you don't need to, and it just ends up being harder to follow and potentially introducing logical bugs (like the image one). It seems that the structure of this file will always be consistent. If so, you can forgo some looping and go straight for the pieces of data you're looking for. You could do something like this:
// Get story header & detail
$stories = $xml->xpath('/NewsML/NewsItem/NewsComponent/NewsComponent');
foreach ($stories as $story) {
$headlineItem = $story->xpath('NewsComponent/ContentItem/DataContent/nitf/body/body.head/hedline/hl1');
$headline = $headlineItem[0];
$detailItems = $story->xpath('NewsComponent/ContentItem/DataContent/nitf/body/body.content/p');
$strDetail = '<p>' . implode('</p><p>', $detailItems) . '</p>';
$imageItem = $story->xpath('NewsComponent/NewsComponent/NewsComponent/ContentItem[#Href]');
$imageAtts = $imageItem[0]->attributes();
$dbImage = $imageAtts['Href'];
$link = getUnique($headline);
$sql = "INSERT INTO tablename (headline, detail, image, link) VALUES ('".mysql_real_escape_string($headline)."', '".mysql_real_escape_string($strDetail)."', '".mysql_real_escape_string($dbImage)."', '".$link."')";
if (mysql_query($sql, $db) or die(mysql_error())) {
echo "Loaded ";
} else {
echo "Not Loaded ";
}
}

drupal------how to output it

this is the code in my module file. if i only want to print the second or the third value or another value., how should i do?
function alterlink_address(){ //page callback function
$sql = db_query("SELECT field_link_url FROM {content_type_address}");
while ($q = db_fetch_object($sql)){
return $q->field_link_url.'<br>';
}
}
I'm no drupal expert and there will surely be a more economic way, but this will still work:
function alterlink_address(){ //page callback function
$sql = db_query("SELECT field_link_url FROM {content_type_address}");
while ($q = db_fetch_object($sql)){
$results[] = $q->field_link_url.'<br>';
}
return $results[0]."<br />";
}
Where the 0 in square brackets is the number (starting from 0) of the result you want to return.
A couple of notes:
a correct indentation can save lives;
getting a plethora of results from the database and displaying just a few of them is a nice method to awaken Cthulhu. I suggest you take a look at the drupal docs to get directly just the results you need.

Categories