Tuesday, January 24, 2012

Turn a word into an array in PHP

Was mucking around with creating a little word game the other day and needed to turn a string in to an array, this is how it was done:

$word = 'words';
$len = strlen($word);
$exploded_word = array();

for($i = 0; $i < $len; $i++) {
    $exploded_word[] = $word[$i];
}
Would produce:
Array
(
    [0] => w
    [1] => o
    [2] => r
    [3] => d
    [4] => s
)

Labels: ,

Monday, January 9, 2012

Looping through select fields and getting the selected text using jQuery

I spent a little time wrestling with this and I thought it may come in useful to pop on to the blog. In my situation I had to loop through a number of select items as I needed to post some data. I needed to do this as I had to pass 3 sets of information from each select / drop down box. It had to be done this way because I was using the dropdown boxes for a number of different functions, some needed to pull the text and some needed to pull the value.
  • The name of the select box
  • The value of the select box
  • The text of the selected item
$('select').each(function(){
     var selected_text = $(this).children('option:selected').text();
})
Happy programming :)

Labels: , ,

Thursday, January 5, 2012

Work out the days between two dates using PHP

I've popped this up as I needed to work out the number of dates in between two dates. Again something similar might be out there, but I thought it may be useful for any one out there that may need it.

Parameters

Required - date1 and date2: Dates in the following format yyyy-mm-dd
Optional - inclusive: If you set to true it includes the two provided dates in it's calculation
Optional - return format of the dates: Combination of PHP's date formatting options

Return Values

Returns an array of dates and the number of days

The Code

/**
    * Get the difference between two dates...
    * @param string $date1 yyyy-mm-dd
    * @param string $date2 yyyy-mm-dd
    * @param boolean $inclusive
    * @param string $return format
    *
    * @return array of total number of days and the dates in the prescribed format
*/

function days_between($date1, $date2, $inclusive = true, $return_format = 'Y-m-d') {
       
        $date_array = array();
        $output_array = array();
       
        $date1_ts = strtotime($date1);
        $date2_ts = strtotime($date2);
        $second_difference = $date2_ts-$date1_ts;
        $num_days = floor($second_difference / 86400);
     
        if (is_numeric($num_days) && $num_days > 0) {
         
            for ($i = 0; $i <= $num_days; $i++) {
                $new_day = $date1_ts + ($i*86400);
                $date_array[] = date($return_format,$new_day);
            }

            if (!$inclusive) {
                unset($date_array[0]);
                array_pop($date_array);
            }
         
            $output_array['number_of_days'] = sizeof($date_array);
            $output_array['dates_between'] = $date_array;  
         
        }

        return ($output_array);
     
}    
Usage

days_between('2011-12-31', '2012-01-05', 1,'d M Y');

Labels: ,

Friday, December 30, 2011

Use search with Codeigniter pagination

Like I mentioned in a previous post, Codeigniter is extremely flexible and the following code is a perfect example of this. This post on using search with Codeigniter pagination uses only standard Codeigniter functions and requires no extra classes or functions.

Benefits to using this method

No need to use any caching to pass information across pages
No need to use any JavaScript / jQuery to amend links
You can pass any number of parameters through the $_GET array - these may include number of links per page, result ordering information etc. as it rebuilds the URL at page load

Downsides

You are using GET which isn't really the Codeigniter way

Notes on usage

This solution requires a form submitted through GET

The beauty of this method is that it allows the programmer to use any number of form fields. There is no need to use a session cookie to keep track of what a user is searching for, it is all done through the $_GET array.

The example uses some pretty standard stuff in terms of Codeigniter. I have called my model 'm_db_results', but that will probably be something completely different in your application. You could also improve the script by writing a better method for counting your results, I use this method for brevity only.

For all other info or help, just follow the inline help :)

public function search() {
 
    $this->load->model('m_db_results');                
    $this->load->library('pagination');
 
    //you can add any key => value parameter to your base_url
    //it just needs one to create a well formed GET request
    $config['base_url'] = '/site/search/?search=true';        

    // as we are unsure as to what values are going to passed to your pagination page
    // we need to build the base url on the fly  
    foreach ($_GET as $key=>$value) {
       if ($key != 'search' && $key != 'offset') {
           $config['base_url'] .= '&'.$key.'='.$value;
       }
    }
 
    //this will need to go to a model method which determines the total number of results
    //based on your form/search parameters. In my case the model method takes an array which in this case
    //is based on key/value pairs that are same mapped the same as the form inputs
    $results_info = $this->m_db_results->search($_GET);
 
    //the key to using this is that it will append your uri with the query string segment parameter
    //using this allows in conjunction with the $config['page_query_string'] being set to true
    //as it adds the offset to the URI as &offset=x
    $config['query_string_segment'] = 'offset';
    $config['page_query_string'] = true;

    $config['total_rows'] = count($results_info);
    $config['per_page'] = $number_per_page = 10;
 
    //now instead of using the uri segment to determine the number of results we offset
    //from our results we use the parameter we specified above in the $config['query_string_segment']      
    if (!empty($_GET['offset'])) {
       $offset = $_GET['offset'];
    } else {
       $offset = 0;
    }

   $this->pagination->initialize($config);
 
    //now we run the same method as above but we supply an amount of results we want to be returned and the offset
    //as the second and third parameters
    //and pass off the data to our view
    $data['results'] = $this->m_db_results->search($_GET, $number_per_page, $offset);
    $this->load->view('results-page.php', $data);

}

Further info

Now as your form is submitted through get, it will not be able to use the set_value() method if you normally use that to repopulate your forms. You will have to code it in yourself, more than likely using isset() or empty() to determine if the field has a value.

P.S. If you found this post useful or not, can you leave some feedback in the comments as I want to improve the code as much as I can for other 'igniter fans. Thanks

Labels: , , ,

Saturday, November 19, 2011

Using PHP to backup an entire MySQL server

This post can be used as a free way to use PHP to backup your MySQL server. The code below comes from a script I developed so that we could back up the server with the execution of a single PHP page. Due to the way the script works, it passes off most of the heavy lifting to the system using exec() function so that it doesn't have to run through the webserver. It does this by using the mysqldump client program that is installed on the MySQL server - The PHP script is just used as a trigger. This is especially helpful if a non-technical person needs to run a database backup, yet doesn't know how to use console commands.

A few notes:
  • Each database is backed up in to it's own file and zipped up using gzip - make sure you have it installed. If not, you can always remove the zip command. 
  • The database script also adds the date to the file name
  • If you do not want to backup the entire database, just alter the database_list array with the names of the databases you want to backup, i.e.
$database_list = array('database_1', 'database_2');
Usage:

To use the script, all you have to do is modify the connection variables at the top and make sure your dump folder has the correct permissions.
  1. I List databases using a little bit of PHP and add them to an array
  2. Loop through the databases
The script:
set_time_limit(0);
$username = 'username';
$password = 'password';
$host = 'localhost';
/**
* Put your path here - Can be any valid path, but remember that you must have write permission on the folder
*/
$dump_path = './dumps/';
$dbc = mysqli_connect($host,$username,$password);
$result = mysqli_query($dbc,'SHOW DATABASES'); 
$database_list = array();
while($row = mysqli_fetch_array($result)) {
   $database_list[] = $row['Database'];
}
foreach ($database_list as $database) {
    $dump_name = $database.'_'.date('d-m-y');
    $dump_string = 'mysqldump --host '.$host.' --user='.$username.' --password='.$password.' '.$database.' > '.$dump_path.$dump_name.'.sql';
    exec($dump_string);
    $zip_cmd = 'gzip '.$dump_path.$dump_name.'.sql';
    exec ($zip_cmd );
}
mysqli_close($dbc);
Download
If you would like to download the script, you may get it here

Expansion
Another one of the benefits of using the exec() function is that it can easily adapted to perform scheduled, reliable backups using a CRON job. This is one of the reasons I used the date() function to append the backup name, so that you could have more than copy of the database in the same directory. One further modification to the script you could perform is to sub categorise your database backups so that they are easier to manage.

James

Labels: , ,

Everyday MySQL console commands and MySQL hints

PHPMyAdmin is a great tool, but due its web based nature it can sometimes fall a little short, especially when dealing with large amounts of data. Don't get me wrong, it's still very useful for browsing large data sets, but if you are looking to do imports, exports, adding indexes etc., then you really need to use the console or some other application.

To be honest, most of the commands here, you will find on many other websites, I just wanted to compile this list as a reference: All the following commands were ran using the console in BASH, but should work on Windows/Mac consoles.

Logging in with a supplied username and using password option:

mysql --user=your_username -p

Logging in with a supplied username and a supplied password:

mysql --user=your_username --password=your_password

Logging in to a different host with a supplied username and password:

mysql --host  host_address --user=your_username --password=your_password

List databases

SHOW DATABASES;

Select a table

USE table_name;

Add an index

When you have a million plus records, this can save so much time in your lookups. I had a table that 1.5 million records, using a single WHERE clause on a non-index field was taking around 1.9 seconds, adding an index reduced the time to 0.0005 seconds:

ALTER TABLE table_name add index (column_name);

Export a database to a file:

mysqldump --user=your_username --password=your_password database_name > name_and_path_of_sql_file_to_create.sql

Will use a modification of the above to show how you can use PHP to backup an entire database in a future post - you can read that here: backup up your MySQL server with PHP

Import a database on to a different host with a supplied username and password:

mysql --host host_address --user=your_username --password=your_password db_name < your_sql_file.sql

Hope this is of use to you.

James



Labels: ,

Sunday, August 28, 2011

Sage Pay Success URI Crypt Length Problems

I have just looking at sage pay form integration and I came across a little problem with success part of the process.

This is how the sage pay flow works:

1. Server sends transaction details and user along to their server for payment.
2. Server authenticates payment and sends back the user to a page you specified in your crypt field in step 1.
3. At this point the payer should be at this point:

http://test.com/success.php?crypt=stringToBeDecrypted

In my case stringToBeDecrypted was 640 characters long and posed a little problem. In my case the string was showing as empty, yet when I ran the same URI on my test server it worked no problem. An investigation was necessary...

It turns out it is to do with Suhosin security patch that many LAMP installations come with and one of it's directives:

suhosin.get.max_value_length

To check your value, just run PHP info and look under your Suhosin section, the value you will probably see is 512 (as this is the default). You will need to change to a figure of at least 640 for your SagePay confirmation page to run. If you have root access to the system then follow the instructions here on how to change the values:

http://solidservers.ca/2008/06/suhosin-changing-configuration-values/

Otherwise contact the server administrators and ask them to change it on your behalf.

Firms

Labels: , , ,