Call to a member function getAttribute() on a non-object [duplicate] - php

This question already has answers here:
Reference - What does this error mean in PHP?
(38 answers)
Closed 8 years ago.
This is the error I got :
Fatal error: Call to a member function getAttribute() on a non-object
in /home/a4688869/public_html/random/index.php
on line 45
Here is a picture: http://prntscr.com/5rum9z
The function works for the first few, but breaks after a few pictures are displayed. Essentially the code generates a random html. I use cURL to get the html and then parse it with a function and then select an image from the site and then repeat the process until it I get 5 images.
My code
$original_string = '123456789abh';
$random_string = get_random_string($original_string, 6);
//Generates a random string of characters and returns the string
function get_random_string($valid_chars, $length)
{
$random_string = ""; // start with an empty random string
$num_valid_chars = strlen($valid_chars); // count the number of chars in the valid chars string so we know how many choices we have
// repeat the steps until we've created a string of the right length
for ($i = 0; $i < $length; $i++)
{
$random_pick = mt_rand(1, $num_valid_chars); // pick a random number from 1 up to the number of valid chars
// take the random character out of the string of valid chars
// subtract 1 from $random_pick because strings are indexed starting at 0, and we started picking at 1
$random_char = $valid_chars[$random_pick-1];
$random_string .= $random_char; // add the randomly-chosen char onto the end of our string so far
}
return $random_string;
}
//Parses the random website and returns the image source
function websearch($url){
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$html = curl_exec($ch);
curl_close($ch);
$dom = new DOMDocument;
#$dom->loadHTML($html); // Had to supress errors
$img = $dom->getElementsByTagName('img')->item(1); //Get just the second picture
$src = $img->getAttribute('src'); //Get the source of the picture
return $src;
}
The part of the code that displays the html
for ($i = 0; $i < $perpage; $i++){
$random_string = get_random_string($original_string, 6);
$src = websearch('http://prntscr.com/' . $random_string);
while( $src == "http://i.imgur.com/8tdUI8N.png"){
$random_string = get_random_string($original_string, 6);
$src = websearch('http://prntscr.com/' . $random_string);
}
?>
<img src="<?php echo $src; ?>">
<p><?php echo $src; ?></p>
<?php if ($i != $perpage - 1){ // Only display the hr if there is another picture after it ?>
<hr>
<?php }}?>

Whenever you get "non-object" errors it is because you are calling a method on a variable that is not an object.
This can be remedied by always checking your return values. It may not be very elegant, but computers are stupid and if you want your code to work then you have to always make sure that it does what you want it to do.
$img = $dom->getElementsByTagName('img')->item(1);
if ($img === null) {
die("The image was not found!");
}
You should also get in the habit of reading the documentation for stuff that you are using (in this case the return values).
DOMDocument
DOMDocument::getElementsByTagName
DOMNodeList
DOMNodelist::item
As you can see on the DOMNodelist::item page the return value, if the method failed, is null:
Return Values
The node at the indexth position in the DOMNodeList, or NULL if that is not a valid index.

Related

Prevent an link becoming double encoded in PHP

I have the following URL in a MySQL database for a PHP application - part of our system allows a user to edit their previous post with these links and save - however as the url gets encoded again when a user edits this is then breaks the url as displayed below.
Is there an easy way or existing PHP function to determine if the string already has been encoded and to alter the string to remove the unwanted characters so it remains in the expected output below.
Expected output
url:https://r5uy4lmtdqka6a1rzyexlusfl-902rjcrzfe6k93co7a644-tom.s3.eu-west-2.amazonaws.com/Carbon%20Monoxide/Summer%20CO%20Campaign/CO%20Summer%202022/CO%20Summer%20you%20can%20smell%20the%20BBQ%20-%20600x600.jpg
Actual output
url:https://r5uy4lmtdqka6a1rzyexlusfl-902rjcrzfe6k93co7a644-tom.s3.eu-west-2.amazonaws.com/Carbon%2520Monoxide/Summer%2520CO%2520Campaign/CO%2520Summer%25202022/CO%2520Summer%2520you%2520can%2520smell%2520the%2520BBQ%2520-%2520600x600.jpg
As suggested in comments, double decode, then encode (only the query string part).
<?php
$str = "https://r5uy4lmtdqka6a1rzyexlusfl-902rjcrzfe6k93co7a644-tom.s3.eu-west-2.amazonaws.com/Carbon%2520Monoxide/Summer%2520CO%2520Campaign/CO%2520Summer%25202022/CO%2520Summer%2520you%2520can%2520smell%2520the%2520BBQ%2520-%2520600x600.jpg";
$str = "https://r5uy4lmtdqka6a1rzyexlusfl-902rjcrzfe6k93co7a644-tom.s3.eu-west-2.amazonaws.com/Carbon%20Monoxide/Summer%20CO%20Campaign/CO%20Summer%202022/CO%20Summer%20you%20can%20smell%20the%20BBQ%20-%20600x600.jpg";
function fix_url($str)
{
$arr = explode('/', $str, 4);
$qs = $arr[3]; // add if at all check?
while (true) {
$decoded = urldecode($qs);
if ($decoded == $qs) {
break;
}
$qs = $decoded;
}
$encoded = urlencode($decoded);
$result = $arr[0] . '//' . $arr[2] . $encoded;
return $result;
}
echo fix_url($str);

Fetching image from google using dom

I want to fetch image from google using PHP. so I tried to get help from net I got a script as I needed but it is showing this fatal error
Fatal error: Call to a member function find() on a non-object in C:\wamp\www\nq\qimages.php on line 7**
Here is my script:
<?php
include "simple_html_dom.php";
$search_query = "car";
$search_query = urlencode( $search_query );
$html = file_get_html( "https://www.google.com/search?q=$search_query&tbm=isch" );
$image_container = $html->find('div#rcnt', 0);
$images = $image_container->find('img');
$image_count = 10; //Enter the amount of images to be shown
$i = 0;
foreach($images as $image){
if($i == $image_count) break;
$i++;
// DO with the image whatever you want here (the image element is '$image'):
echo $image;
}
?>
I am also using Simple html dom.
Look at my example that works and gets first image from google results:
<?php
$url = "https://www.google.hr/search?q=aaaa&biw=1517&bih=714&source=lnms&tbm=isch&sa=X&ved=0CAYQ_AUoAWoVChMIyKnjyrjQyAIVylwaCh06nAIE&dpr=0.9";
$content = file_get_contents($url);
libxml_use_internal_errors(true);
$dom = new DOMDocument;
#$dom->loadHTML($content);
$images_dom = $dom->getElementsByTagName('img');
foreach ($images_dom as $img) {
if($img->hasAttribute('src')){
$image_url = $img->getAttribute('src');
}
break;
}
//this is first image on url
echo $image_url;
This error usually means that $html isn't an object.
It's odd that you say this seems to work. What happens if you output $html? I'd imagine that the url isn't available and that $html is null.
Edit: Looks like this may be an error in the parser. Someone has submitted a bug and added a check in his code as a workaround.

Trying to scrape images from reddit, having trouble cleaning up strings

So I'm not asking for you to fix my script, if you know the answer I would appreciate it if you just pointed me in the right direction. This is a script I found and I'm trying to edit it for a project.
I believe that whats going on is the formatting of $reddit is causing problems when I input that string into $url. I am not sure how to filter the string.
Right after I posted this I had the idea of using concatenation on $reddit to get the desired result instead of filtering the string. Not sure.
Thanks!
picgrabber.php
include("RIS.php");
$reddit = "pics/top/?sort=top&t=all";
$pages = 5;
$t = new RIS($reddit, $pages);
$t->getImagesOnPage();
$t->saveImage();
RIS.php
class RIS {
var $after = "";
var $reddit = "";
public function __construct($reddit, $pages) {
$this->reddit = preg_replace('/[^A-Za-z0-9\-]/', '' , $reddit);
if(!file_exists($this->reddit)) {
mkdir($this->reddit, 0755);
}
$pCounter = 1;
while($pCounter <= $pages) {
$url = "http://reddit.com/r/$reddit/.json?limit=100&after=$this->after";
$this->getImagesOnPage($url);
$pCounter++;
}
}
private function getImagesOnPage($url) {
$json = file_get_contents($url);
$js = json_decode($json);
foreach($js->data->children as $n) {
if(preg_match('(jpg$|gif$|png$)', $n->data->url, $match)) {
echo $n->data->url."\n";
$this->saveImage($n->data->url);
}
$this->after = $js->data->after;
}
}
private function saveImage($url) {
$imgName = explode("/", $url);
$img = file_get_contents($url);
//if the file doesnt already exist...
if(!file_exists($this->reddit."/".$imgName[(count($imgName)-1)])) {
file_put_contents($this->reddit."/".$imgName[(count($imgName)-1)], $img);
}
}
}
Notice: Trying to get property of non-object in C:\Program Files (x86)\EasyPHP-DevServer-13.1VC9\data\localweb\RIS.php on line 33
Warning: Invalid argument supplied for foreach() in C:\Program Files (x86)\EasyPHP-DevServer-13.1VC9\data\localweb\RIS.php on line 33
Fatal error: Call to private method RIS::getImagesOnPage() from context '' in C:\Program Files (x86)\EasyPHP-DevServer-13.1VC9\data\localweb\vollyeballgrabber.php on line 23
line 33:
foreach($js->data->children as $n) {
var_dump($url);
returns:
string(78) "http://reddit.com/r/pics/top/?sort=top&t=all/.json?limit=100&after=" NULL
$reddit in picgrabber.php has GET parameters
In the class RIS, you're embedding that value into a string that has another GET set in it with the ".json" token between.
The resulting url is:
http://reddit.com/r/pics/top/?sort=top&t=all/.json?limit=100&after=
The ".json" token needs to come after the end of the location portion of the url and before the GET sets. I would also change any addition "?" tokens to "&" (ampersands) so any additional sets of GET parameters you decide to concatenate to the URL string become additional parameters.
Like this:
http://reddit.com/r/pics/top/.json?sort=top&t=all&limit=100&after=
The difference is, your url is returning html code because the reddit server doesn't understand how to parse what you're sending. You're trying to parse html with a json decoder. My URL returns actual json data. That should get your json decoder returning an actual json object array.

PHP - Multi Curl - scraping for data/content

I have started building a single Curl session with - curl, dom, xpath, and it worked great.
I am now building a scraper based off curl for taking data off multiple sites in one flow, and the script is echo'ing the single phrase i put in.. but it does not pick up variables.
do{
$n=curl_multi_exec($mh, $active);
}while ($active);
foreach ($urls as $i => $url){
$res[$i]=curl_multi_getcontent($conn[$i]);
echo ('<br />success');
}
So this does echo the success-text as many times as there are urls.. but really this is not what i want.. I want to break up the html like i could with the single curl session..
What i did in the single curl session:
//parse the html into a DOMDocument
$dom = new DOMDocument();
#$dom->loadHTML($res);
// grab all the on the page
$xpath = new DOMXPath($dom);
$product_img = $xpath->query("//div[#id='MAIN']//a");
for ($i = 0; i < $product_img->length; $i++){
$href = $product_img->item($i);
$url = $href->getAttribute('href');
echo "<br />Link : $url";
}
This dom parsing / xpath is working for the single session curl, but not when i run the multicurl.
On Multicurl i can do curl_multi_getcontent for the URL from the session, but this is not want..
I would like to get the same content as i picked up with Dom / Xpath in the single session.
What can i do ?
EDIT
It seems i am having problems with the getAttribute. It is a link for an image i am having trouble grabbing. The link is showing when scraping, but then it throws an error :
Fatal error: Call to a member function getAttribute() on a non-object in
The query:
// grab all the on the page
$xpath = new DOMXPath($dom);
$product_img = $xpath->query("//img[#class='product']");
$product_name = $xpath->query("//img[#class='product']");
This is working:
for ($i = 0; i < $product_name->length; $i++) {
$prod_name = $product_name->item($i);
$name = $prod_name->getAttribute('alt');
echo "<br />Link stored: $name";
}
This is not working:
for ($i = 0; i < $product_img->length; $i++) {
$href = $product_img->item($i);
$pic_link = $href->getAttribute('src');
echo "<br />Link stored: $pic_link";
}
Any idea of what i am doing wrong ?
Thanks in advance.
For some odd reason, it is only that one src that won't work right.
This question can be considered "solved".

Return value without numeric and punctuations

I'm trying to strip the numeric and punctuations from a string leaving only alpha characters in SIMPLE HTML DOM, with no success I've tried multiple approaches and just can't get it!
Example string: The Amazing Retard (2012) #1
Output string: The Amazing Retard
I understand it's for an undefined method and I've looked at multiple pages for this, however I'm brain farting for how to include the method. Any help would be appreciated. The error that I get is
Fatal error: Call to undefined method simple_html_dom_node::preg_replace() in /home/**/public_html/wp-content/themes/*/***.php on line 123
The code is as follows:
<?php
function scraping_comic()
{
// create HTML DOM
$html = file_get_html('http://page-to-scrape.com');
// get block
foreach($html->find('li.browse_result') as $article)
{
// get title
$item['title'] = trim($article->find('h4', 0)->find('span',0)->outertext);
// get title url
$item['title_url'] = trim($article->find('h4', 0)->find('a.grid-hidden',0)->href);
// get image
$item['image_url'] = trim($article->find('img.main_thumb',0)->src);
// get details
$item['details'] = trim($article->find('p.browse_result_description_release', 0)->plaintext);
// get sale info
$item['on_sale'] = trim($article->find('.browse_comics_release_dates', 0)->plaintext);
// strip numbers and punctuations
$item['title2'] = trim($article->find('h4',0)->find('span',0)->preg_replace("/[^A-Za-z]/","",$item['title2'], 0)->plaintext);
$ret[] = $item;
}
// clean up memory
$html->clear();
unset($html);
return $ret;
}
// -----------------------------------------------------------------------------
$ret = scraping_comic();
if ( ! empty($ret))
{
$scrape = 'http://the-domain.com';
foreach($ret as $v)
{
echo '<p>'.$v['title2'].'</p>';
echo '<p>'.$v['title'].'</p>';
echo '<p><img src="'.$v['image_url'].'"></p>';
echo '<p>'.$v['details'].'</p>';
echo '<p> '.$v['on_sale'].'</p>';
}
}
else { echo 'Could not scrape site!'; }
?>
preg_replace is a php function, not a member of the simple_html_dom_node class. call it like this:
$matches = preg_replace ($pattern, $replacement, mixed $subject);
http://php.net/manual/en/function.preg-replace.php
it looks like your $pattern and replacement are OK; you'll just pass in as the $subject the input you're trying to change.
for example, this might be what you're trying to achieve:
$item['title2'] =
trim(preg_replace("/[^A-Za-z]/","",$article->find('h4',0)->find('span',0));
I think it's because of this line :
// strip numbers and punctuations
$item['title2'] = trim($article->find('h4',0)->find('span',0)->preg_replace("/[^A-Za-z]/","",$item['title2'], 0)->plaintext);
written like this it means that preg_replace is a method of your class simple_html_dom_node which is not as it's standard php function.
you might have in your class something like execute_php_function("a_php_function",anArrayOfArguments)
so you'll write something like this :
// strip numbers and punctuations
$item['title2'] = trim($article->find('h4',0)->find('span',0)->execute_php_function("preg_replace",anArrayOfArguments)->plaintext);

Categories