Tag Archives: php

PHP strtotime WTF!

So I just spent almost a day chasing a (what I thought it was) a bug in my code regarding dates.

I needed to add a month to a specific date  so I can bill ongoing contracts, but the returned date sometimes where full “calendar” months other times it was 31 days.

Let me show:

echo date("Y-m-d", strtotime("+1 month 2011-11-21"));
returns: 2011-12-21 // appears to be right

echo date("Y-m-d", strtotime("+1 month 2011-11-30"));
returns: 2011-12-30 // wtf? but I wanted 2011-12-31

echo date("Y-m-d", strtotime("+1 month 2011-12-15"));
returns:  2012-01-15 // hum? that is right

echo date("Y-m-d", strtotime("+1 month 2012-01-31"));
returns: 2012-03-02 // wtf? I wanted 2012-02-29

echo date("Y-m-d", strtotime("+1 month 2012-01-01"));
returns: 2012-02-01 // oh! that's right

echo date("Y-m-d", strtotime("+1 month 2012-02-01"));
returns: 2012-03-01 // sigh... That's right to what's going on here?

As you can see above sometimes PHP return full calendar months other 31 days. Fortunately there’s a pattern:

The way I see it if the day is not in the end of the month PHP will add a calendar month if it’s in the end of the month PHP will add the number of days that the current month has.

So if you want to make sure PHP always adds a calendar month to your date this is how I did it:

$tmp_date1 = strtotime("+1 day", strtotime("2012-01-31"));
$tmp_date2 = strtotime("+1 month", $tmp_date1);
$final_date = date('Y-m-d', strtotime("-1 day", $tmp_date2));

This ensures that if your date is in the end of the month strtotime will make calculation with the beginning of the month that way full calendar months will be added instead of number of days that current month has.

Reddit discussion about this

FuelPHP Input arrays validation

After pulling some hair and digging a lot in FuelPHP core I finally discovered a litle hack that allows validation of input arrays and its re-population using FuelPHP Validation Class.

Here’s how I did it:

View simplified for the sake of the example:

<?php echo \Form::label("Price", "options[0][price]"); ?>
<?php echo \Form::input("options[0][price]", \Validation::instance()->input("options.0.price"); ?>

<?php echo \Form::label("Name", "options[0][name]"); ?>
<?php echo \Form::input("options[0][name]", \Validation::instance()->input("options.0.name"); ?>

<?php echo \Form::label("Price", "options[1][price]"); ?>
<?php echo \Form::input("options[1][price]", \Validation::instance()->input("options.1.price"); ?>

<?php echo \Form::label("Name", "options[1][name]"); ?>
<?php echo \Form::input("options[1][name]", \Validation::instance()->input("options.1.name"); ?>

Mind the options.0.name instead of options[0]name inside the Validation Input.

In my controller I did this:

$val = \Validation::factory();

if ( \Input::post("options") )
{
    $form_options = \Input::post("options");

    foreach ( $form_options as $form_id => $option )
    {
        $val->add("options.{$form_id}.price", "{$option["name"]} price")
                ->add_rule("required")
                ->add_rule("match_pattern", '/[0-9]*(\.|,)?[0-9]+/');

        $val->add("options.{$form_id}.name", "{$option["name"]} name")
                ->add_rule("required");

    }
}

 

And that’s it, this should validate the fields and repopulating them in case of errors. It’s a bit stupid that it only works like this.

FuelPHP should provide a friendlier way and a documented one to validate array input fields, it’s a common feature when dealing with dynamic built forms that have one-to-many objects in it.

 

Tested with FuelPHP 1.0.1

FuelPHP BreadCrumb Class/Library

Morning,

Just finish building a breadcrumb Class for FUELPHP.

This Class has persistent crumbs, meaning that visited crumbs will be saved in session.

GitHub link for FuelPHP-BreadCrumb

Read more »

Check if all function arguments are equal in PHP

Question: Could this be written better?

private function compareThree($val_1, $val_2, $val_3)
{
    return (($val_1 == $val_2) && ($val_1 == $val_3) && ($val_2 == $val_1) && ($val_2 == $val_3) && ($val_3 == $val_2) && ($val_3 == $val_1));
}

Short Answer: Yes! That’s horrible and makes my eyes bleed.

Long Answer: Why compare only three? Why not build a function that compares a infitine number of arguments and check if they are all equal. Here’s my solution:

function compareAllTheArguments()
{
    return count(array_unique(func_get_args())) === 1;
}

Explanation:

func_get_args() // Get all function arguments in array list

 array_unique() // Removes duplicate values from an array

count() // Well, yeah, returns the number of elements in a array

Knowing this first we get all the arguments in the function then remove all the duplicates and if it’s only one left that means all elements are equal.

Get last key from array in PHP

The fastest and the correct way to get the last key from an array is:

$lastkey = array_pop(array_keys($arr));

Example:

$arr[] = array("red" => "apple", "yellow" => "banana");

Let’s say you want to add another element to the previous created array, for that you need to know the last created index so:

$lastkey = array_pop(array_keys($arr));
$arr[$lastkey]["brown"] = "kiwi";

And there you have it.

FuelPHP version 1.0 is out

After 9 months in the oven here it is, the first oficial version of one of my personal favorities PHP frameworks.

FUEL is great for several reason, has a great  autoload system, DB class is greatly implemented and although I have not tested it ORM look sweet. The only thing I miss at the time I’m writing this is a official Email Class that I’m sure it will be out in a near future.

My advice is for you to try it, you’ll not be disappointed. Also if you need help the community in freenode channel #fuelphp is very friendly and helpful. Offcourse you always have the foruns.

The list of commits is huge, check if here: http://mjs.me/aB

Official blog post about it: http://mjs.me/aC

 

WEBSITE | GITHUB | DOWNLOAD v1.0

New version of URL Shortener mjs.me

MJS.ME

Shrink that huge URL

 

Just released a new version of http://mjs.me url shortener.

This is a complete rebuild using FuelPHP, it’s a great PHP framework and very fun to code with.

There still some missing features that I want to incorporate, I’ll release updates soon.

I have open source it, if you want to make changes feel free to check the code and send pull requests :)

DEMO | DOWNLOAD | SOURCE

Codeigniter 2.0.1 is out

Nice to see a fast development process in the Codeigniter forge!

The changelog copy pasta:

Release Date: March, 15, 2011

  • General changes
    • Added $config['cookie_secure'] to the config file to allow requiring a secure (HTTPS) in order to set cookies.
    • Added the constant CI_CORE to help differentiate between Core: TRUE and Reactor: FALSE.
    • Added an ENVIRONMENT constant in index.php, which affects PHP error reporting settings, and optionally, which configuration files are loaded (see below). Read more on the Handling Environments page.
    • Added support for environment-specific configuration files.
  • Libraries
    • Added decimal, less_than and greater_than rules to the Form validation Class.
    • Input Class methods post() and get() will now return a full array if the first argument is not provided.
    • Secure cookies can now be made with the set_cookie() helper and Input Class method.
    • Added set_content_type() to Output Class to set the output Content-Type HTTP header based on a MIME Type or a config/mimes.php array key.
    • Output Class will now support method chaining.
  • Helpers
    • Changed the logic for form_open() in Form helper. If no value is passed it will submit to the current URL.

Bug fixes for 2.0.1

  • CLI requests can now be run from any folder, not just when CD’ed next to index.php.
  • Fixed issue #41: Added audio/mp3 mime type to mp3.
  • Fixed a bug (Core #329) where the file caching driver referenced the incorrect cache directory.
  • Fixed a bug (Reactor #69) where the SHA1 library was named incorrectly.

 

 

Download at: http://codeigniter.com/download.php

Regex 01 – Alphanumeric Strings

// Allow alphanumeric only
$pattern = "/^[A-Za-z0-9]+$/";

// Allow alphanumeric with spaces
$pattern = "/^[A-Za-z0-9 ]+$/ ";

// Allow alphanumeric with underscore and dashes
$pattern = "/^[A-Za-z0-9_-]+$/";

// Allow alphanumeric with underscore, dashes, and spaces
$pattern = "/^[A-Za-z0-9_- ]+$/";

Testing Strings Using preg_match()

if( preg_match( $pattern, "This is a string 1234" ) ) {
    echo "Match";
} else {
    echo "No match";
}

Upload files using PHP Function

UPDATE: DON’T USE THIS I WAS YOUNG AND STUPID!

Here is a simple couple of function that allow you to upload files to your server, read the php comments for how to

	/* Upload file to the webserver
	 * Parameters:
	 * $fileObjectArray - The $_FILE array, you should pass something like $_FILE['myUploadedFile']
	 * $AllowExtensions - The extensions that you want to allow to be uploaded - Eg: $AllowExtensions = array('jpg','gif'); 
	 * $AllowedSize - Max allowed size in Bytes
	 * $destinyFolder - Your files destiny folder - Eg: Uploads
	 * $fileName - Optinional file name, if you don't pass it, will be generated a unique file name
	 */
	function uploadFile($fileObjectArray, $AllowExtensions, $AllowedSize, $destinyFolder, $fileName = null){
		/* $_FILE Array proprieties explanation
		* [name] => MyFile.txt (comes from the browser, so treat as tainted)
		* [type] => text/plain  (not sure where it gets this from - assume the browser, so treat as tainted)
		* [tmp_name] => /tmp/php/php1h4j1o (could be anywhere on your system, depending on your config settings, but the user has no control, so this isn't tainted)
		* [error] => UPLOAD_ERR_OK  (= 0)
		* [size] => 123   (the size in bytes)
		*/

		/* Error values
		* 1 - $_FILE array not been set
		* 2 - File extension not allowed
		* 3 - File size bigger than defined
		* 4 - Could not move file from tmp do specified location
		* 5 - destiny folder does not exists
		*/

		//Check if $_FILE as been set
		if ($fileObjectArray['error'] != 0) {
			return 1;
		}else{
			$formFileName = $fileObjectArray['name'];
			$formFileExtension = $this->findFileExtension($formFileName);
			$formTmpPath = $fileObjectArray['tmp_name'];
			$formFileSize = $fileObjectArray['size'];
		}

		//Check if a custom file name as been passed if not gives unique id to it
		if ($this->is_empty($fileName)) {
			$fileName = $this->unique_id().'.'.$formFileExtension;
		}

		//Validates extension based on $AllowExtensions array parameter
		foreach ($AllowExtensions as $ext){
			if ($ext == $formFileExtension){
				break;
			}else{
				return 2;
			}
		}

		//Validates filesize based on $AllowedSize parameter
		if ($formFileSize > $AllowedSize) {
			return 3;
		}
		
		if (!file_exists($destinyFolder)) {
			return 5;
		}

		//Main part
		$fullDestinyPath = $destinyFolder.'/'.$fileName;
		if (!move_uploaded_file($formTmpPath,$fullDestinyPath)) {
			return 4;
		}else{
			return $fileName;
		}

	}

	function unique_id(){
		$better_token = md5(uniqid(rand(), true));
		$unique_code = substr($better_token, 16);
		$uniqueid = $unique_code;
		return $uniqueid;
	}


	function is_empty($var, $allow_false = false, $allow_ws = false) {
		if (!isset($var) || is_null($var) || ($allow_ws == false && trim($var) == "" && !is_bool($var)) || ($allow_false === false && is_bool($var) && $var === false) || (is_array($var) && empty($var))) {
			return true;
		} else {
			return false;
		}
	}

	function findFileExtension($filename){
		$filename = strtolower($filename) ;
		$exts = split("[/\\.]", $filename) ;
		$n = count($exts)-1;
		$exts = $exts[$n];
		return $exts;
	}