Simple Html Dom Fatal error: Call to a member function on a non-object

Simple Html Dom is a PHP dom manipulator. This library is one of the easiest and most powerful dom manipulator for PHP. In fact, you can even use this to create your own web crawler like what i have done. However, Simple Html Dom library isn't perfect. Although you are able to do almost everything without a problem using simple htm dom, the most problematic thing that will happen in a complex program would be to have different combination of URL. The combination of a URL is endless and this can cause simple html dom to fail.

I faced this problem with simple html dom where fatal error keep stopping my php crawler using simple html dom. The fatal error always occurs around "call to a member function on a non-object at...." and when I look at the fatal error link being process, it was perfectly fine. In PHP, we cannot really stop a fatal error without using some black magic which not always work. Like many people would have say, prevention is better than cure. Hence, doing a checking to determine whether the variable is an object before proceeding will definitely fixed this problem. If you think like many other people out there, this is most likely what you would have done and bet that it will definitely fix your problem.

$html = file_get_html($url);
if(is_object($html)){
   foreach($html->find('img') as $img){
      //bla bla bla..
   }
}

Well, the above might work in some case but not all. when file_get_html failed, it will return false regardless of 404 or 500 occurs on the other side of the server. Hence, you may do this as well,

$html = file_get_html($url);
if($html){
   foreach($html->find('img') as $img){
      //bla bla bla..
   }
}

But if it still doesn't solve your problem which it really shouldn't be able to take care of all cases, you might turn to do the following,

$html = file_get_html($url);
if($html && is_object($html)){
   foreach($html->find('img') as $img){
      //bla bla bla..
   }
}

Well, if this still doesn't work and your brain is stuck, you might feel lucky this time that you come to this blog of mine.

Simple_Html_Dom Fatal Error Solution

The solution for your problem is actually quite simple but not direct. However, i have tested this with almost few hundred thousands of different URL so i can confirm you that this will definitely solve your fatal error and get rid of the "call to a member function on a non-object" especially when it reaches "find". The solution is simple, using the above example, we will just have to add in a condition where it doesn't fail and the object was created by simple html dom class but it doesn't contain any node! In this case, you should write something like the following,

$html = file_get_html($url);
if($html && is_object($html) && isset($html->nodes)){
   foreach($html->find('img') as $img){
      //bla bla bla..
   }
}

In the above example, i uses all the true condition but in my real program i was using all the false condition (is false). But it should still works. I tested this for a few days as the bot was required to run for a few lots of hours before i bang into a fatal error. This is really a wasteful of time. But the solution is rewarding. I hope this help some fellow out there 🙂

How to extract word from a string given a position in php

Today i wanted to extract a particular word or text (if the word doesn't make sense) given a position in a string. I tried to search this for php platform but couldn't really find an answer for it. In facts, i cannot find any through google for such functionality in php. However, i manage to find it on python. It was actually pretty simple and straight forward and i believe most of people will get it in one look. But we don't revamp the wheel so here you go.

      function extractWord($text, $position){
         $words = explode(' ', $text);
         $characters = -1; 
         foreach($words as $word){
            $characters += strlen($word);
            if($characters >= $position){
               return $word;
            }   
         }   
         return ''; 
      }   

pretty easy isn't it? The above will basically split the string into individual word and loop these words and calculate the total position. If the position of the total characters is larger or equal to the position you provide, we have reach the word that we want. Here is a little example on how to extract word from a string given a position.

$text = 'This is an example of how to extract word from a string given a position in php
$position = strpos($text, 'examp');
$word = extractWord($text, $position); // return example

It's pretty simple and straight forward but it does save some time and focus on something more important. Hope it helps 🙂

Determine Whether JavaScript Is Enabled/Disabled Via PHP

Recently i was working on a project where there is a need to determine whether JavaScript is enabled or was disabled by the user. Depending whether the JavaScript is enable or not, the system will rely on JavaScript operation if it does and PHP operation if it doesn't. The fundamental solution to this is to detect whether JavaScript is enable before the system can determine which approach can be used. However, there is no easy solution to determine whether a client scripting is enable in a server scripting language (PHP) without finish loading the page! Therefore, in this article we will discuss whether there is such possibility to use PHP to determine whether JavaScript is enabled for your web application.

The Problem

The main problem is that a server script language can never be able to determine whether a client script language is available as the server script language will always run first. Furthermore, the client script is always run on the client side and never executed on the server side. Therefore, when the server scripting is running at the server side and send to the client for display, the server scripting language will have no idea what is going on with the client environment. Hence, strictly speaking will be unable to determine JavaScript is enable or disable.

The Solution

Although it sounds impossible for server side to determine whether a client scripting is available such as JavaScript but certain tricks can be perform in order to achieve this. However, it won't be a convenient one. Recall that every web system should have a redirect index.php page to prevent our code from showing in plaintext if anything happen? We can use that page to determine whether javascript is enable by writing a script to either append a value and post over to the next page or a better alternative is to store it into the user cookie. If you store a value and post it to the next page, the validation can only occur within the main page. However, if you utilize cookie to determine whether JavaScript is available, you can always use php to determine whether that cookie value is available. If it is not available (they delete their browser cookie on the way) you can redirect that user to the index.php to revalidate JavaScript is enable. Once it is being verify, you will just show a message to the user after index.php has redirect or run on pure php.

On the index.php script, it will be something like this,

<script type='javascript/text'>
function createCookie(name,value,days) {
	if (days) {
		var date = new Date();
		date.setTime(date.getTime()+(days*24*60*60*1000));
		var expires = "; expires="+date.toGMTString();
	}
	else var expires = "";
	document.cookie = name+"="+value+expires+"; path=/";
}
createCookie('verify_cookie', 'Y', 1);
</script>
<meta http-equiv="refresh" content="2;url=main.php?c=1">

We have a function that help us to create a cookie if JavaScript available. Once this is done, we redirect the user to main.php where our real page is located with a get value of c=1. This value is needed to avoid recursive request. We can't use PHP header function because it will redirect before JavaScript has the opportunity to run and the code should be placed before the head tag to make this valid. On all other pages we will have something like this before the header.

<?php
	//filter the global variable first.
	if(!isset($_COOKIE['verify_cookie']) && $_GET['c'] == 1){
		echo 'JavaScript is disable';
	}else if(!isset($_COOKIE['verify_cookie'])){
		//perform check to determine whether the cookie expire OR it really was disabled.
		header('location: index.php');
	}else{
		//perform another check on javascript similar to index.php if you afraid that the cookie exist but javascript was disabled.
	}
?>

The above is to verify whether javascript exist in each page and use to run either pure php or combination with JavaScript as these script can be imported using PHP if needed. The solution above can be use as a references and not necessary a solid solution.

Alternative Solution

The alternative solution to this is to use the noscript tag which is very simple and make your life a better place to live in.

<script>
document.getElementsByTagName('body')[0].innerHTML = 'JavaScript is enable.';
<script>
<noscript>
JavaScript is disabled.
<noscript>

Conclusion

Many will turn to noscript tag that can really ease and simplify the way we code. However, for some system which required to determine whether script is enabled for different server script to run. This might help those that are doing such approach as noscript tag will only run after the server has processed its information. On the other hand, you can combine this approach with the no tag approach to better validate your logic.

25 PHP Form Validation Snippets

Recently i have involve myself in another application development. Regular Hungred Dot Com visitors will notice that the site currently offer advertisement space through this form. But really, we as a developers are always looking for such snippets or writing them out from scratch every single time regardless of how many time we know we have store it somewhere in our laptop! Man, its really frustrating searching on Google and find all sort of solution and trying to figure out whether the regular expression implemented is expensive or complete. So i came out with an idea to ease my life a bit and other developers by putting up an article such as this for my/our references. (This can be made into a class if you like to)

Validate Email

We can perform an email validation through this function.

	function isValidEmail($email){
		return eregi('^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$', $email);
	}

After fainted for a few seconds when i saw unreal4u finding, i decided to throw up preg_match solution instead.

	function isValidEmail($email){
		return preg_match('/^[_a-z0-9-]+(\.[_a-z0-9-]+)*@[a-z0-9-]+(\.[a-z0-9-]+)*(\.[a-z]{2,3})$/i', $email);
	}

PHP 5.2 and above.

function fnValidateEmail($email)
{
  return filter_var($email, FILTER_VALIDATE_EMAIL);
}

Sanitize Email

We can further sanitize our email to ensure that everything is alright.

function fnSanitizeEmaill($string) {
     return  preg_replace( '((?:\n|\r|\t|%0A|%0D|%08|%09)+)i' , '', $string );
}

PHP 5.2 and above.

function fnSanitizeEmaill($url)
{
  return filter_var($url, FILTER_SANITIZE_EMAIL);
}

Validate Email Exist

This is not possible but certain validation can be use to validate email existence.

function check_email($email)
{
	$email_error = false;
	$Email = htmlspecialchars(stripslashes(strip_tags(trim($email)))); //parse unnecessary characters to prevent exploits
	if ($Email == '') { email_error = true; }
	elseif (!eregi('^([a-zA-Z0-9._-])+@([a-zA-Z0-9._-])+\.([a-zA-Z0-9._-])([a-zA-Z0-9._-])+', $Email)) { email_error = true; }
	else {
	list($Email, $domain) = split('@', $Email, 2);
		if (! checkdnsrr($domain, 'MX')) { email_error = true; }
		else {
		$array = array($Email, $domain);
		$Email = implode('@', $array);
		}
	}

	if (email_error) { return false; } else{return true;}
}

Validate Number Only

We can use PHP built-in function to validate whether a given value is a number.

function fnValidateNumber($value)
{
	#is_ double($value);
	#is_ float($value);
	#is_ int($value);
	#is_ integer($value);
	return is_numeric($value);
}

PHP 5.2 and above.

function fnValidateNumber($value)
{
	#return filter_var($value, FILTER_VALIDATE_FLOAT); // float
	return filter_var($value, FILTER_VALIDATE_INT); # int
}

Sanitize Number

We can force all value to be only numeric by sanitize them.

function fnSanitizeNumber($str)
{
	#letters and space only
	return preg_match('/[^0-9]/', '', $str);
}

PHP 5.2 and above.

function fnSanitizeNumber($value)
{
	#return filter_var($value, FILTER_SANITIZE_NUMBER_FLOAT); // float
	return filter_var($value, FILTER_SANITIZE_NUMBER_INT); # int
}

Validate String Only

Sometimes to validate name we can use this function to restrict only letters and spaces.

function fnValidateStringr($str)
{
	#letters and space only
	return preg_match('/^[A-Za-z\s ]+$/', $str);
}

Sanitize String

We can sanitize it instead of validate user input.

function fnSanitizeStringr($str)
{
	#letters and space only
	return preg_replace('/[^A-Za-z\s ]/', '', $str);
}

PHP 5.2 and above. built-in function by PHP provides a much more powerful sanitize capability.

function fnSanitizeStringr($str)
{
	return filter_var($str, FILTER_SANITIZE_STRIPPED); # only 'String' is allowed eg. '<br>HELLO</br>' => 'HELLO'
}

Validate Alphanumeric Characters

This validates alphanumeric characters.

function fnValidateAlphanumeric($string)
{
	return ctype_alnum ($string);
}

Sanitize Alphanumeric Characters

This sanitize alphanumeric characters. eg. "HELLO! Do we have 90 idiots running around here?" => "HELLO Do we have 90 idiots running around here"

function fnSanitizeAlphanumeric($string)
{
	return preg_replace('/[^a-zA-Z0-9]/', '', $string);
}

Validate URL Exist

This function will check whether a given URL exist and not only validate it.

	function url_exist($url)
	{
		$url = @parse_url($url);

		if (!$url)
		{
			return false;
		}

		$url = array_map('trim', $url);
		$url['port'] = (!isset($url['port'])) ? 80 : (int)$url['port'];
		$path = (isset($url['path'])) ? $url['path'] : '';

		if ($path == '')
		{
			$path = '/';
		}

		$path .= (isset($url['query'])) ? '?$url[query]' : '';

		if (isset($url['host']) AND $url['host'] != @gethostbyname($url['host']))
		{
			if (PHP_VERSION >= 5)
			{
				$headers = @get_headers('$url[scheme]://$url[host]:$url[port]$path');
			}
			else
			{
				$fp = fsockopen($url['host'], $url['port'], $errno, $errstr, 30);

				if (!$fp)
				{
					return false;
				}
				fputs($fp, 'HEAD $path HTTP/1.1\r\nHost: $url[host]\r\n\r\n');
				$headers = fread($fp, 4096);
				fclose($fp);
			}
			$headers = (is_array($headers)) ? implode('\n', $headers) : $headers;
			return (bool)preg_match('#^HTTP/.*\s+[(200|301|302)]+\s#i', $headers);
		}
		return false;
	}

Validate URL Format

This function will validate a given url to ensure the format is correct.

function fnValidateUrl($url){
return preg_match('/^(http(s?):\/\/|ftp:\/\/{1})((\w+\.){1,})\w{2,}$/i', $url);
}

PHP 5.2 and above.

function fnValidateUrl($url)
{
  return filter_var($url, FILTER_VALIDATE_URL);
}

Sanitize URL

PHP 5.2 and above.

function fnSanitizeUrl($url)
{
  return filter_var($url, FILTER_SANITIZE_URL);
}

Validate Image Exist

This function will check whether a given image link exist and not only validate it.

	function image_exist($url) {
	if(@file_get_contents($url,0,NULL,0,1)){return 1;}else{ return 0;}
	}

Validate IP Address

This function will validate an IP address.

function fnValidateIP($IP){
	return preg_match('/^(([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]).){3}([1-9]?[0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/',$IP)
}

PHP 5 and above. This can also specific validation for IPV4 or IPV6.

function fnValidateIP($ip)
{
  return filter_var($ip, FILTER_VALIDATE_IP);
}

Validate Proxy

This function will let us detect proxy visitors even those that are behind anonymous proxy.

function fnValidateProxy(){
	if ($_SERVER['HTTP_X_FORWARDED_FOR']
	   || $_SERVER['HTTP_X_FORWARDED']
	   || $_SERVER['HTTP_FORWARDED_FOR']
	   || $_SERVER['HTTP_VIA']
	   || in_array($_SERVER['REMOTE_PORT'], array(8080,80,6588,8000,3128,553,554))
	   || @fsockopen($_SERVER['REMOTE_ADDR'], 80, $errno, $errstr, 30))
	{
		exit('Proxy detected');
	}
}

Validate Username

Before we validate whether a given username is matches the one in our database, we can perform a validation check first to prevent any unnecessary SQL call.

function fnValidateUsername($username){
	#alphabet, digit, @, _ and . are allow. Minimum 6 character. Maximum 50 characters (email address may be more)
	return preg_match('/^[a-zA-Z\d_@.]{6,50}$/i', $username);
}

Validate Strong Password

Another good thing is to validate whether a particular password given by the user is strong enough. You can do that using this function which required the password to have a minimum of 8 characters, at least 1 uppercase, 1 lowercase and 1 number.

function fnValidatePassword($password){
	#must contain 8 characters, 1 uppercase, 1 lowercase and 1 number
	return preg_match('/^(?=^.{8,}$)((?=.*[A-Za-z0-9])(?=.*[A-Z])(?=.*[a-z]))^.*$/', $password);
}

Validate US Phone Number

This function will validate US phone number for US users.

function fnValidateUSPhone($phoneNo){
	return preg_match('/\(?\d{3}\)?[-\s.]?\d{3}[-\s.]\d{4}/x', $phoneNo);
}

Validate US Postal Code

This function validate US postal code.

function fnValidateUSPostal($postalcode){
	#eg. 92345-3214
	return preg_match('/^([0-9]{5})(-[0-9]{4})?$/i',$postalcode);
}

Validate US Social Security Numbers

This function validate US Social Security Numbers.

function fnValidateUSSocialSecurityCode($ssb){
	#eg. 531-63-5334
	return preg_match('/^[\d]{3}-[\d]{2}-[\d]{4}$/',$ssn);
}

Validate Credit Card

This function validate credit card format.

function fnValidateCreditCard($cc){
	#eg. 718486746312031
	return preg_match('/^(?:4[0-9]{12}(?:[0-9]{3})?|5[1-5][0-9]{14}|6011[0-9]{12}|3(?:0[0-5]|[68][0-9])[0-9]{11}|3[47][0-9]{13})$/', $cc);
}

Validate Date

This is a date format MM-DD-YYYY or MM-DD-YY validation which validate from year 0000-9999.

function fnValidateDate($date){
	#05/12/2109
	#05-12-0009
	#05.12.9909
	#05.12.99
	return preg_match('/^((0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01])[- /.][0-9]?[0-9]?[0-9]{2})*$/', $date);
}

This is a date format YYYY-DD-MM or YY-MM-DD validation which validate from year 0000-9999.

function fnValidateDate($date){
	#2009/12/11
	#2009-12-11
	#2009.12.11
	#09.12.11
	return preg_match('#^([0-9]?[0-9]?[0-9]{2}[- /.](0?[1-9]|1[012])[- /.](0?[1-9]|[12][0-9]|3[01]))*$#'', $date);
}

Validate Hexadecimal Colors

This is a good validation for people who allows their user to change color in their system.

function fnValidateColor($color){
	#CCC
	#CCCCC
	#FFFFF
	return preg_match('/^#(?:(?:[a-f0-9]{3}){1,2})$/i', $color);
}

Make Query Safe

This function help sanitize our data to be SQL injection safe.

function _clean($str){
return is_array($str) ? array_map('_clean', $str) : str_replace('\\', '\\\\', htmlspecialchars((get_magic_quotes_gpc() ? stripslashes($str) : $str), ENT_QUOTES));
}

//usage call it somewhere in beginning of your script
_clean($_POST);
_clean($_GET);
_clean($_REQUEST);// and so on..

Make Data Safe

This function help to keep us protected against XSS, JS and SQL injection by removing tags.

function _clean($str){
return is_array($str) ? array_map('_clean', $str) : str_replace('\\', '\\\\', strip_tags(trim(htmlspecialchars((get_magic_quotes_gpc() ? stripslashes($str) : $str), ENT_QUOTES))));
}

//usage call it somewhere in beginning of your script
_clean($_POST);
_clean($_GET);
_clean($_REQUEST);// and so on..

Summary

A paranoid way to perform a form validation would be to validate first then sanitize your values for precautions. If you think the above snippets were suck or you have any good or awesome snippets to share. Please throw your comment and share with us!

Integrate Paypal Express Checkout Solution

As a web developer, there will surely be someday where you wish to integrate Paypal into one of your products or services. The most appropriate way is to read the documentation provided by Paypal. But reading it doesn't mean you will understand the documentation with one shot and this call for a lot of research and finding before your Paypal will work. I went through this process these few days that is why there wasn't much article written in the process.  Although it wasn't really difficult but going through the process of reading first before looking into their sample codes really wasn't the correct way of approaching this solution. Instead, looking into the sample code will definitely brings light to integrating Paypal express checkout solution (well, you still have to read a bit). In this article, i will try to demonstrate Paypal express checkout solution as simple as possible for you guys to be able to DIY.

Paypal Express Checkout

What is Paypal Express checkout solution? Paypal Express Checkout makes it easier for your customers to pay and allows you to accept PayPal while retaining control of the buyer and overall checkout flow. This means that you can integrate a payment solution with Paypal that retain most of the interaction on your website other than user login and verifying the product they are purchasing. Paypal express checkout also provides you with the ability to create recurring payment which can really eliminate the need to repurchase the exact service or product every single time. However, Paypal express checkout solution doesn't have the ability to allow your user to use credit card for purchases. Your customers must have Paypal in order to purchase with this solution. Credit card solution will only be available together with Paypal in Website Payment Pro solution. Hopefully this clear some doubt and help you select what solution you really need.

Integrate Paypal Express Checkout Solution - Step 1

Firstly, you might wonder where exactly are the correct documentation out of all the places in Paypal. You can get the documentation and Sample at the respective links. The sample is contain at the section PayPal API: Name-Value Pair Interface as i believe this will give you a better understanding on the flow of Paypal express check out solution. The sample files will required you to throw them  into your server and run (go to the browser and key in the url you have thrown the folder into) as it will simulate some of the payment flow you might want. Then you will look into the code and see how they are achieved. Please take note that localhost might not work for you as it will required you to have curl installed.

Integrate Paypal Express Checkout Solution - Step 2

Once the sample are placed into your server and you have play around, the next thing you might wonder is the exact file you will required to run your own Paypal express checkout solution. And here are the files you will only need.

  • APIError - display error
  • CallerService - main player that initial the talk
  • constants - all the required variables
  • SetExpressCheckout - display for step 1 of the process
  • GetExpressCheckoutDetails - display for step 2 of the process
  • DoExpressCheckoutPayment -  display for step 3 of the process + send final request to paypal
  • ReviewOrder - request handler for step 1 and responsible to redirect to step 2

The files i am looking at are all PHP files.  Well, the above file respective function should be self explained. The first 3 files(APIError, CallerService and Constants) are the files imported into the ReviewOrder and  DoExpressCheckoutPayment files as they are required to talk to Paypal. Once we understand this it is time to go into a more complicated stuff.

Integrate Paypal Express Checkout Solution - Step 3

To illustrate what is going on in the sample file, we will look at the following diagram provided by Paypal.

From left to right, we have 5 interfaces user will see. And two of them are display from Paypal where it is colored in blue (2nd and 3rd interface). Hence, we left with 3 interfaces which are SetExpressCheckout, GetExpressCheckoutDetails and DoExpressCheckoutPayment which is 1st, 4th and 5th interface respectively.  So we are all clear with the display files right now. Next we will need to know where ReviewOrder will appear. There are altogether 4 Calcuts as written on the diagram. The ReviewOrder will be triggered on the 2nd and 3rd Calcuts where SetExpressCheckout API and GETExpressCheckoutDetails API is being fired. Don't worry about what does these API means at the moment. Just treat them as a method that will tell Paypal what they do.

Integrate Paypal Express Checkout Solution - Step 4

I guess everyone should understand how Paypal work looking at the sample file and the explanation above.  Next i will explain some of the important things you will need to know since writing all the codes here is meaningless as they are the same for every sample files. It just makes it more confusing to read. Firstly, for each request made to Paypal, you will always see the following line in the sample file.

$resArray=hash_call("SetExpressCheckout",$nvpstr);

where $nvpstr is the name-value pair string passed into the method hash_call. What this function hash_call does it to send the request to Paypal to notify them the action you performing. In this case, SetExpressCheckout API is being performed here. There are also other API as mention previous such as GetExpressCheckoutDetails API and DoExpressCheckoutPayment API. These are the three API you will need to talk to Paypal in each stage shown on the previous diagram. So we should all clear about what does API mean that are written all over the Paypal documentation. The next important step is to know what name-value pair does each API required you to send in order for Paypal to understand you.

Integrate Paypal Express Checkout Solution - Step 5

Here we will see what does each API in the process of express checkout required. For SetExpressCheckout, you will required to have the following name-value pair in your string.

  • AMT
  • CURRENCYCODE
  • RETURNURL
  • CANCELURL
  • PAYMENTACTION

That is all! But in the sample it gives you more than just the above which is pretty good to understand what can be dump into the nvp string for it to display what you want on the paypal website where your user gets redirected.

For GetExpressCheckoutDetails API is pretty simple. It will just required you to have a token passed into the nvp string and this token can be retrieved via $_GET method where Paypal send it through there.

Lastly, for DoExpressCheckoutPayment API, you will need to provide the following nvp for it to work.

  • TOKEN
  • PAYERID
  • AMT
  • CURRENCYCODE
  • PAYMENTACTION

And that's it! The value forGetExpressCheckoutDetails and DoExpressCheckoutPayment API are provided by Paypal during the process while SetExpressCheckout data are given by you.

Summary

I believe the above explanations were pretty clear. But i still used quite a hell lots of time working on it *SLAP MYSELF*! This article is intended to provide any newbie on Paypal to get the hang of integrating Paypal without the need to spend time on reading and learning all about Paypal integration. However, the sample provided by Paypal is not secure and is only used to serve as a demonstration on 'how integration can be made easy'. I believe this article will be pretty useful for anyone to understand how Paypal work rather than reading few thousand words given by Paypal and never direct you to the correct sources or code (other than more documentation). Guess what? I found this Paypal Integration Wizard which is a wizard that creates all the above codes for you! :[