Sometimes called the rule of three, this is how you calculate the percentage of a number from another number.
For example, you have 2 numbers, 34 and 116. Let’s say 116 is the total number (100%), and we want to find out what percentage is 34 out of 100%.
Here’s how:
<?php
function percentage($amount, $total, $decimal = 2) {
if (0 === (int)$total) {
return $total;
}
return number_format((((int)$amount / (int)$total) * 100), $decimal);
}
echo percentage(34, 116) . '%';
?>
It’s simple math.
One of my clients asked me to monitor her site’s uptime. While this script is not yet complete, and it should use a CRON job and a mail()
function, here’s how to check for uptime and current HTTP status code:
<?php
$toCheckURL = 'https://getbutterfly.com/'; // The domain name of the site you want to check
// This all sets up the CURL actions to check the page
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $toCheckURL);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_NOBODY, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_MAXREDIRS, 10); //follow up to 10 redirections - avoids loops
$data = curl_exec($ch);
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); // Get the HTTP Code
// Get final redirected URL, will be the same if URL is not redirected
$new_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
curl_close($ch);
// Array of HTTP status codes. Trim down if you would like to.
$codes = array(
0 => 'Domain Not Found',
100 => 'Continue',
101 => 'Switching Protocols',
200 => 'OK',
201 => 'Created',
202 => 'Accepted',
203 => 'Non-Authoritative Information',
204 => 'No Content',
205 => 'Reset Content',
206 => 'Partial Content',
300 => 'Multiple Choices',
301 => 'Moved Permanently',
302 => 'Found',
303 => 'See Other',
304 => 'Not Modified',
305 => 'Use Proxy',
307 => 'Temporary Redirect',
400 => 'Bad Request',
401 => 'Unauthorized',
402 => 'Payment Required',
403 => 'Forbidden',
404 => 'Not Found',
405 => 'Method Not Allowed',
406 => 'Not Acceptable',
407 => 'Proxy Authentication Required',
408 => 'Request Timeout',
409 => 'Conflict',
410 => 'Gone',
411 => 'Length Required',
412 => 'Precondition Failed',
413 => 'Request Entity Too Large',
414 => 'Request-URI Too Long',
415 => 'Unsupported Media Type',
416 => 'Requested Range Not Satisfiable',
417 => 'Expectation Failed',
500 => 'Internal Server Error',
501 => 'Not Implemented',
502 => 'Bad Gateway',
503 => 'Service Unavailable',
504 => 'Gateway Timeout',
505 => 'HTTP Version Not Supported'
);
// Check if we have a valid HTTP code from the above list
if (isset($codes[$http_code])) {
echo 'Website returned status code: ' . $http_code . ' - ' . $codes[$http_code] . '<br>';
// Get the headers from the $data to the $matches variable
preg_match_all("/HTTP\/1\.[1|0]\s(\d{3})/", $data, $matches);
array_pop($matches[1]); // Remove the last status that we just displayed above which should be 200
if (count($matches[1]) > 0) {
// Loop through all other matches to see what other status codes we got
foreach ($matches[1] as $c) {
echo $c . ' - ' . $codes[$c] . '<br>';
}
}
// Can use this to check if the URL is still the same as you checked
// Or if the server has moved
if ($toCheckURL != $new_url) {
echo 'URL has changed to: ' . $new_url;
}
}
// This is just to show you the headers of the website you are checking
echo '<hr><pre>';
var_dump($data);
echo '</pre>';
?>
Further steps would involve adding the data to a database and creating charts and graphs.
Let’s suppose you don’t use WordPress or another CMS that allows you to bulk optimise your JPEG images. Let’s suppose you have multiple folders and it’s nearly impossible to use an online optimizer due to directory restrictions or volume of work.
So, you create a PHP file called io.php
and add the following code:
<?php
ini_set('memory_limit', '512M');
ini_set('max_execution_time', 600); // 10 minutes
$dir = "uploads/{*.jpg}";
// Open a known directory, and proceed to read its contents
$images = array();
foreach (glob($dir, GLOB_BRACE) as $key => $img) {
echo 'Optimising <b>' . $img . '</b>...<br>';
$image = imagecreatefromjpeg($img);
imagejpeg($image, $img, 60); // from 0 to 100 (percentage)
}
?>
Save it, upload it to your site root using your FTP client and run it – example.com/io.php
. After several minutes, the listing stops and all your images have been optimised.
The only variables you need to modify are the directory path (uploads in the code above) and the level of compression (usually 60 to 75 is the most common).
So, you pushed all your values to an array, and now you need to calculate the average value. Even if you have thousands of values, this function will iterate through all array items and return the average value:
<?php
function get_average($numbers, $decimals) {
$a = $numbers;
$b = 0;
$c = 0;
$d = 0;
foreach ($a as $b) {
$c = $c + $b;
$d++;
}
return number_format($c/$d, $decimals);
}
?>
This is how you display the average value:
<?php
$myarray = array();
// push elements to array
echo get_average($myarray, 2);
?>
The function works both with integer values and with float values. Make sure you actually declare the variable as an array before pushing items into it. Some PHP versions might complain about this. Use var_dump($myarray)
or print_r($myarray)
to check if your array is well-formed.
As a bonus, this is how I use print_r()
:
<?php
function array_dump($array) {
echo '<pre>';
print_r($array);
echo '</pre>';
}
?>
Enjoy!
Let’s suppose you want to create a small PHP function to archive various folders on your server. I had to code a plugin to generate archives from various folders for a site with no FTP access (don’t ask).
Excluding the WordPress specific code, here’s the HTML form:
<form method="post" action="" name="zipMe">
<p><input type="text" name="folderPath" id="folderPath" placeholder="Path to your directory..."> <label for="folderPath">Path to your directory</label></p>
<p>input type="submit" name="zipMeNow" value="Zip and download"></p>
</form>
Here’s the PHP code:
<?php
if (isset($_POST['zipMeNow'])) {
$folderPath = $_POST['folderPath']; // sanitize this value
ini_set('max_execution_time', 3600); // increase PHP execution time for large files
// get path for the folder // I have zipped the /themes/ folder as an example
$rootPath = '/home/xxxxxxxx/public_html/wp-content/themes/';
$zip = new ZipArchive();
$zip->open('file.zip', ZipArchive::CREATE | ZipArchive::OVERWRITE); // change filename or make it dynamic
$files = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($rootPath), RecursiveIteratorIterator::LEAVES_ONLY);
foreach ($files as $name => $file) {
if (!$file->isDir()) { // skip directories (they will be added automatically)
// get real and relative path for current file
$filePath = $file->getRealPath();
//$relativePath = substr($filePath, strlen($rootPath) + 1); // use this if you get a corrupt archive
$relativePath = substr($filePath, strlen($rootPath));
// add current file to archive
$zip->addFile($filePath, $relativePath);
}
}
// Zip archive will be created only after closing object
$zip->close();
// send headers to force download the file // or send it to Dropbox or Google Drive
header("Content-type: application/zip");
header("Content-Disposition: attachment; filename=file.zip");
//header("Content-length: " . filesize('file.zip')); // not necessary
header("Pragma: no-cache");
header("Expires: 0");
readfile("file.zip");
exit;
}
?>
You don’t need to worry as the ZipArchive is a native PHP class. I am checking for its existence inside WordPress using this code:
<?php
if (class_exists('ZipArchive')) {
echo 'ZipArchive class exists';
}
?>
What you can improve:
Once in a while you feel the need to remove all your domain related cookies in your browser, or force the user to remove them.
Sometimes you set the wrong cookies or set a too high expiration date for them and you can’t rename them and you can’t politely ask the user to delete them. But you can redirect the user to a special file. This is where Cookie Cleaner comes into play.
Cookie Cleaner uses both PHP and JavaScript in order to completely remove any cookie traces from your browser. The browser needs to be restarted in order for the process to complete.
Grab the code from GitHub and test it yourself.
Feel free to contribute and share your cookie monster sessions.
PHP has a feature that allows you to prepend a file at every request. This prepend file is the equivalent of having it include()ed at the top of every single PHP script on your site. It’s is done through a directive that is set either in php.ini
or .htaccess
. The directive is called auto_prepend_file. It’s also evil if you don’t know about its existence.
In a .htaccess
file, you can use this directive to define a specific file that will be auto-prepended, in a directory:
php_value auto_prepend_file "prepend.php"
You can also use this directive to deactivate auto-prepending in a directory or root:
php_value auto_prepend_file none
Note: Use the special value “none
“, as explained in the documentation of auto_prepend_file
:
The special value none disables auto-prepending.
Note: You can set php_values in .htaccess
only where PHP is run as an Apache module.
When I first encountered this issue, I blamed my text editor for byte order marks (BOM). So, I found a neat script that searches for BOM files inside your root and recursively throughout the folders:
<?php
error_reporting(E_ALL);
// Detect BOM sequence in a folder recursively
define('STR_BOM', "\xEF\xBB\xBF");
$file = null;
$directory = getcwd();
$rit = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($directory), RecursiveIteratorIterator::CHILD_FIRST);
try {
foreach ($rit as $file) {
if ($file->isFile()) {
$path_parts = pathinfo($file->getRealPath());
if ('php' == $path_parts['extension']) {
$object = new SplFileObject($file->getRealPath());
if (false !== strpos($object->getCurrentLine(), STR_BOM)) {
print $file->getRealPath()."\n";
}
}
}
}
} catch (Exception $e) {
die ('Exception caught: '. $e->getMessage());
}
?>
There! Issue fixed!
This function emulates WordPress wpautop()
function for custom PHP scripts, parses URL addresses and adds smilies/emoticons.
<br>
) into a paragraph.<br>
, making a SHIFT+ENTER
new line.The following script is a helper library for dynamic badge creation using either static data or MySQL information. Static data may include Facebook information or other social stats. The application sends a link via email leading to the generated badge. All badges are stored online on the host site.
Get it, fork it or contribute!
You need PHP with GD library and a MySQL database.
This is a PHP contact form with spam check and honeypot features. Note that there’s plenty of room for improvement, so feel free to fork it or add a pull request.
I recently had to turn a static localized CRM into a multilanguage one. The obvious solution, without relying on gettext functions, was to use PHP arrays.
So, here we go:
First of all we need a configuration setting inside our script’s config.php
file. For the sake of our example, we’ll add a manual variable change:
// language settings
$lng = 'en';
Next, our header file, dubbed header.php
(could be head.php
or top.php
in your script) will contain these lines:
include 'includes/config.php';
include 'languages/' . $lng . '.php';
You now, obviously, have to create a languages directory and create a new file called en.php
. This file will hold our array of words and expressions:
/*
* @Package: My multilanguage script
* @Language: English (English)
*/
$lang = array();
$lang['REGISTER'] = 'Register';
$lang['USERNAME'] = 'Username';
$lang['PASSWORD'] = 'Password';
$lang['LOGIN'] = 'Log in';
$lang['LOGOUT'] = 'Log out';
$lang['DASHBOARD'] = 'Dashboard';
Notice how I tried to keep the array index name as close to translation as possible. For example, you’ll have the string “Separate tags with commas” as $lang['SEPARATE_TAGS_COMMAS']
. It’s easier after a couple of months when you’ll make changes.
Also, try to keep consistent naming of your language files, such as fr.php
, de.php
, ru.php
.
Now, call in you script <?php echo $lang['REGISTER'];?>
. It will display “Register”, just as you translated it in your language file.
One of the latest features I’ve added to my sports fishing portal was the nice date feature. Instead of showing PHP formatted date and time, I wanted to display time since the action took place, like “4 hours ago”, “2 days ago”, “1 minute ago” and so on.
<?php
function nicetime($date) {
if (empty($date)) {
return "ERROR: No date provided";
}
$periods = array("second", "minute", "hour", "day", "week", "month", "year", "decade");
$lengths = array("60", "60", "24", "7", "4.35", "12", "10");
$now = time();
$unix_date = strtotime($date);
// check validity of date
if (empty($unix_date)) {
return "ERROR: Invalid date";
}
// is it future date or past date
if ($now > $unix_date) {
$difference = $now - $unix_date;
$tense = "ago";
} else {
$difference = $unix_date - $now;
$tense = "from now";
}
for ($j = 0; $difference >= $lengths[$j] && $j < count($lengths)-1; $j++) {
$difference /= $lengths[$j];
}
$difference = round($difference);
if ($difference != 1) {
// $periods[$j] .= "s"; // plural for English language
$periods = array("seconds", "minutes", "hours", "days", "weeks", "months", "years", "decades"); // plural for international words
}
return "$difference $periods[$j] {$tense}";
}
?>
Use <?php echo nicetime($date); ?>
to call the function, where $date
is a variable holding your desired date, properly formatted in PHP/MySQL. You can also pass a date directly using the standard format – date('Y-m-d G:i:s')
, but, for obvious reasons, it’s better to prior assign it to a fixed variable.
I had to calculate past dates using 2 separate date and time columns. MySQL uses NOW()
to output a date format such as "2011-03-10 14:30:00"
. My date column was DATE()
– "2011-03-10"
and my time column was TIME()
– "14:30:00"
. So I had to combine them before making the comparison with NOW()
.
The MySQL function for this comparison is:
SELECT * FROM mytable WHERE DATE_ADD(mydate, INTERVAL mytime HOUR_SECOND) <= NOW()
This function will combine both columns into a TIMESTAMP
value, formatted by DATE_ADD
, ready to compare with NOW()
format.
My documentation included more examples such as: SELECT TO_SECONDS('2011-03-10 14:30:00');
and SELECT TO_SECONDS(NOW());
. Calculating the time difference in seconds is easy using these two MySQL functions, though time values such as 00:00:00
will fail.
This is how you format dates any way you want:
date('d/m/Y', strtotime($mydaterow))
date('H:i', strtotime($mytimerow))
This line will display the difference in minutes between two dates:
$toTime = strtotime('2010-10-10 13:48:00');
$fromTime = strtotime('2010-10-10 13:22:00');
echo round(abs($to_time - $from_time) / 60,2) . " minute";
Imagine you can replace the date strings with your own date/time column(s).
And another MySQL line that will select rows within a range of time:
SELECT * FROM table WHERE DATE_ADD(date, INTERVAL time HOUR_SECOND) BETWEEN '2010-01-01 16:30:00' AND '2010-01-02 17:00:00';
If, for any given reason, you are not able to implement a MySQL counter, here is the easiest solution for creating a flat file online users counter. Create a file called online.php
, make it writable, and insert the following code where you want the counter to appear:
<?php
$file_name = 'online.php';
$c_time = time();
$timeout = 60;
$time = $c_time - $timeout;
$ip = getenv("REMOTE_ADDR");
if (!file_exists($file_name)) {
$fp = fopen($file_name, "w");
fwrite($fp, " \n");
fclose($fp);
}
$fp = fopen($file_name, "a");
$write = $ip . "||" . $c_time . "\n";
fwrite($fp, $write);
fclose($fp);
$file_array = file($file_name);
$online_array = array();
for ($x = 1; $x < count($file_array); $x++) {
list($ip, $ip_time) = explode("||", $file_array[$x]);
if ($ip_time >= $time) {
array_push($online_array, $ip);
}
}
$online = array_unique($online_array);
$online = count($online);
if ($online == "1") {
print "$online user online";
} else {
print "$online users online";
}
?>
That’s it!
If you are receiving warnings or even errors about your homepage being accessible both via example.com
and example.com/index.php
, there are two solutions:
Add to your header file, or to your index.php file the following snippet:
<?php
$cpage = $_SERVER['REQUEST_URI'];
if ((string) $cpage === '/' || (string) $cpage === '/index.php') {
echo '<link rel="canonical" href="https://getbutterfly.com/" />';
}
?>
This way, Google (and the other search engines out there) will consider both your root domain and your specified search page as one canonical URL link.
The second solution is using .htaccess
(if available) to redirect index.php
to root, like this:
Options +FollowSymLinks
DirectoryIndex index.php
RewriteEngine On
RewriteBase /
RewriteCond %{THE_REQUEST} ^[A-Z]{3,9}\ /index\.php\ HTTP/
RewriteRule ^index\.php$ http://www.example.com/ [R=301,L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
That’s it!
You might have a text file with a lot of emails, extracted from a mail client or a CSV file created with some script.
Nonetheless, you want to extract all the valid email addresses (user@domain.ext
) from the file. Pass this function a file (you can rename it to .php, or .txt, or .csv) and it will extract all addresses:
function extract_emails_from($string) {
preg_match_all("/[._a-zA-Z0-9-]+@[._a-zA-Z0-9-]+/i", $string, $matches);
return $matches[0];
}
// Usage
extract_emails_from('myfile.txt');
?>
That’s it!
I’ve been trying to enhance one of my current themes with a dynamic header. The header was supposed to show different images with different links to section of the blog. This is what I ended up with. It works perfectly. Feel free to add as many arrays as you want and as many images inside the arrays as you want.
<?php
display_random_img($array) {
$key = rand(0, count($array) - 1);
$link_url = $array[$key]['url'];
$alt_tag = $array[$key]['alt'];
$random_img_url = $array[$key]['img_url'];
list($img_width, $img_height) = getimagesize($random_img_url);
return '';
}
// Edit the following values accordingly
$ads_array = array(
array(
'url' => 'https://www.google.com/',
'alt' => 'Google',
'img_url' => '/path/to/images/1.png',
),
array(
'url' => 'https://www.yahoo.com/',
'alt' => 'Yahoo!',
'img_url' => '/path/to/images/2.png',
),
array(
'url' => 'https://www.msn.com/',
'alt' => 'MSN',
'img_url' => '/path/to/images/3.png',
),
);
echo display_random_img($ads_array);
?>
That’s it!
Have you ever wondered how some web sites show a “loaded in x seconds” or “page created in x seconds” in the footer? Well, it’s a simple PHP script to add.
Add the following code snippet in the page head. For more accurate results, place it above the <!doctype>
declaration:
<!-- put this at the top of the page -->
<?php
$mtime = microtime();
$mtime = explode(' ', $mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime
?>
Then, add the following code snippet where you want your timer to show up (usually in the footer):
<!-- put this code at the bottom of the page -->
<?php
$mtime = microtime();
$mtime = explode(' ', $mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);
echo 'Page loaded in ' . $totaltime . ' seconds.';
?>
PHP’s microtime()
function returns the current Unix timestamp with microseconds. And the explode()
function returns an array of strings, each of which is a substring of string formed by splitting it on boundaries formed by the string separator. If limit is set, the returned array will contain a maximum of limit elements with the last element containing the rest of string.
There are many tiny details that can improve and speed up your PHP script functioning. Here is a list of 42 of them.
echo
is faster than print
.echo
‘s multiple parameters instead of string concatenation.for
loops before and not in the loop.__get
, __set
, __autoload
.require_once
is expensive$_SERVER['REQUEST_TIME']
is preferred to time()
.strncasecmp
, strpbrk
and stripos
instead of regex
.str_replace
is faster than preg_replace
, but strtr
is faster than str_replace
by a factor of 4.if
/else if
statements.@
is very slow.mod_deflate
.$row['id']
is 7 times faster than $row[id]
.for
loop, such as for ($x=0; $x < count($array); $x)
. The count()
function gets called each time.$this->prop++
) is 3 times slower than a local variable.$localvar++
operations. A similar method call is of course about 15 $localvar++
operations.'
instead of "
will make things interpret a little faster since PHP looks for variables inside "..."
but not inside '...'
. Of course you can only do this when you don’t need to have variables in the string.echo
, which is a function that can take several strings as arguments.strlen()
function. This function is pretty quick since it’s operation does not perform any calculation but merely return the already known length of a string available in the zval
structure (internal C struct used to store variables in PHP). However, because strlen()
is a function, it is still somewhat slow because the function call requires several operations such as lowercase & hashtable lookup followed by the execution of said function. In some instance you can improve the speed of your code by using an isset()
trick.Example:
if (strlen($foo) < 5) { echo 'Foo is too short'; }
vs.
if (!isset ($foo{5})) { echo 'Foo is too short'; }
Calling isset()
happens to be faster than strlen()
because, unlike strlen()
, isset()
is a language construct and not a function, meaning that it’s execution does not require function lookups and lowercase. This means you have virtually no overhead on top of the actual code that determines the string’s length.
$i++
happens to be a tad slower than ++$i
. This is something PHP specific and does not apply to other languages, so don’t go modifying your C or Java code thinking it’ll suddenly become faster, it won’t. ++$i
happens to be faster in PHP because instead of 4 opcodes used for $i++
you only need 3. Post incrementation actually causes the creation of a temporary var that is then incremented. While pre-incrementation increases the original value directly.mod_gzip
, which is available as an Apache module, compresses your data on the fly and can reduce the data to transfer up to 80%.While updating one WordPress site this morning, I found a nice plugin, disguised as an .htaccess
redirection towards an index_backup.php
file both in the /plugins/
and the /themes/
directories.
The .htaccess
looked similar to this one:
<IfModule mod_rewrite.c> RewriteEngine On RewriteCond %{HTTP_REFERER} ^.*(google|ask|yahoo|yandex|ya|baidu|youtube|wikipedia|qq|excite|altavista|msn|netscape|aol|hotbot|goto|infoseek|mamma|alltheweb|lycos|search|metacrawler|bing|dogpile|facebook|twitter|blog|live|myspace|linkedin|flickr|filesearch|yell|openstat|metabot|gigablast|entireweb|amfibi|dmoz|yippy|walhello|webcrawler|jayde|findwhat|teoma|euroseek|wisenut|about|thunderstone|ixquick|terra|lookle|metaeureka|searchspot|slider|topseven|allthesites|libero|clickey|galaxy|brainysearch|pocketflier|verygoodsearch|bellnet|freenet|fireball|flemiro|suchbot|acoon|devaro|fastbot|netzindex|abacho|allesklar|suchnase|schnellsuche|sharelook|sucharchiv|suchbiene|suchmaschine|infospace|web|websuche|witch|wolong|oekoportal|freenet|arcor|alexana|tiscali|kataweb|voila|sfr|startpagina|kpnvandaag|ilse|wanadoo|telfort|hispavista|passagen|spray|eniro|telia|bluewin|sympatico|nlsearch|atsearch|klammeraffe|sharelook|suchknecht|ebay|abizdirectory|alltheuk|bhanvad|daffodil|click4choice|exalead|findelio|gasta|gimpsy|globalsearchdirectory|hotfrog|jobrapido|kingdomseek|mojeek|searchers|simplyhired|splut|thisisouryear|ukkey|uwe|friendsreunited|jaan|qp|rtl|apollo7|bricabrac|findloo|kobala|limier|express|bestireland|browseireland|finditireland|iesearch|kompass|startsiden|confex|finnalle|gulesider|keyweb|finnfirma|kvasir|savio|sol|startsiden|allpages|america|botw|chapu|claymont|clickz|clush|ehow|findhow|icq|westaustraliaonline)\.(.*) RewriteCond %{HTTP_USER_AGENT} ^.*(msie|opera) [NC] RewriteCond %{REQUEST_FILENAME} !/index_backup.php RewriteRule (.*) /index_backup.php?query=$1 [QSA,L] </IfModule>
Finding more occurrences of this trojan is accomplished by using one of my PHP functions. Create a new file in your WordPress root, add the code below and run it. It will show one or more files containing potentially malicious code (note that it will also show some WordPress files, which are not infected). Check each file to see how the code looks. Most of the detections will be inside the themes and plugins directories and, sometimes, they will be in the uploads directory.
The trojan has been classified as a PHP agent, PHP trojan or PHP Spambot by various antivirus packages.
Read more about this type of PHP trojan here (link in Russian).
This is an advanced solution used to redirect old links using 301 (or 302, or 504 or whatever code you need) to new links using native PHP functions. If they don’t work, the redirection falls back to an HTML meta refresh. Enjoy!
<?php
/**
* PHP Redirects
*
* @copyright Copyright (c) 2016 getbutterfly.com getButterfly (https://getbutterfly.com)
* @license https://getbutterfly.com New BSD License
*/
/**
* Checks and cleans a URL.
*
* A number of characters are removed from the URL.
*
* @param string $url The URL to be cleaned.
* @return string The cleaned $url.
*/
function php_deep_replace($search, $subject) {
$subject = (string) $subject;
$count = 1;
while($count) {
$subject = str_replace($search, '', $subject, $count);
}
return $subject;
}
function php_esc_url($url) {
$original_url = $url;
if('' == $url)
return $url;
$url = str_replace( ' ', '%20', $url );
$url = preg_replace('|[^a-z0-9-~+_.?#=!&;,/:%@$\|*\'()\[\]\\x80-\\xff]|i', '', $url);
if('' === $url) {
return $url;
}
if(0 !== stripos( $url, 'mailto:')) {
$strip = array('%0d', '%0a', '%0D', '%0A');
$url = php_deep_replace($strip, $url);
}
$url = str_replace(';//', '://', $url);
/* If the URL doesn't appear to contain a scheme, we
* presume it needs http:// prepended (unless a relative
* link starting with /, # or ? or a php file).
*/
if(strpos($url, ':') === false && !in_array($url[0], array('/', '#', '?')) && !preg_match('/^[a-z0-9-]+?\.php/i', $url))
$url = 'http://' . $url;
// Replace ampersands and single quotes only when displaying.
$url = str_replace('&', '&', $url);
$url = str_replace("'", ''', $url);
/**
* Filter a string cleaned and escaped for output as a URL.
*
* @param string $_context
*/
return $url;
}
function php_redirect($url) {
// Sanitize URI
$url = php_esc_url($url);
// Get and append query string
if(!empty($_SERVER['QUERY_STRING'])) {
$url .= '?' . $_SERVER['QUERY_STRING'];
}
$content = sprintf('<!doctype html><html class="no-js"><head><meta charset="utf-8"><meta http-equiv="refresh" content="0;url=%1$s"><title>Redirecting to %1$s...</title></head><body>Redirecting to <a href="%1$s">%1$s</a>...</body></html>', htmlspecialchars($url, ENT_QUOTES, 'UTF-8'));
header('Location: ' . $url, true, 301);
die($content);
}
/**
* Get client URI including arguments.
*/
$getUri = php_esc_url($_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI']);
if(strpos($getUri, 'example.com/old-uri-1') !== false) {
php_redirect('https://www.example.com/new-uri-1');
} else if(strpos($getUri, 'example.com/old-uri-2') !== false) {
php_redirect('https://www.example.com/new-uri-2');
} else if(strpos($getUri, 'example.com/old-uri-3') !== false) {
php_redirect('https://www.example.com/new-uri-3');
}
And just go on with the loop. If you need to integrate it into your CMS, you can use a foreach()
function and loop through your database.
One client requested a simple contact form, without AJAX or other options. So, I used the PHP mail()
function, wrapped in a simple HTML form.
First, we create the HTML form (contact.php
):
<h1>Simple Contact Form</h1>
<form method="post" action="send_contact.php">
<p><input name="subject" type="text" placeholder="Subject"</p>
<p><textarea name="detail" cols="50" rows="4" placeholder="Detail"></textarea></p>
<p><input name="name" type="text" placeholder="Name"></p>
<p><input name="email" type="email" placeholder="Email"></p>
<p><input type="submit" name="Submit" value="Submit"></p>
</form>
Next, we create the email sending engine (send_contact.php
):
<?php
$name = filter_var((string) trim(addslashes($_POST['name'])), FILTER_SANITIZE_STRING);
$subject = filter_var((string) trim(addslashes($_POST['subject'])), FILTER_SANITIZE_STRING);
$message = filter_var((string) trim(addslashes($_POST['detail'])), FILTER_SANITIZE_STRING);
$mailFrom = filter_var((string) trim($_POST['email']), FILTER_VALIDATE_EMAIL);
$headers = "From: $name <$mailFrom>";
// Your email address
$to = 'someone@somewhere.com';
$sendAction = mail($to, $subject, $message, $headers);
// If message was successfully sent, display a message
if ($sendAction) {
echo 'Thank you for your interest. We will get back to you as soon as possible.';
} else {
echo 'Error: The email was not sent. Check your server.';
}
?>
That is all. Note that more code sanitization is required.
1. First create a languages/
directory.
2. Create two language files, let’s say english.php
and spanish.php
and populate them with variables:
english.php
$txt['headtext'] = 'Welcome to our site';
spanish.php
$txt['headtext'] = 'Bienvenido a nuestro sitio';
3. Create an includes/
directory.
4. Create a configuration file:
config.php
<?php
$languages = array(
'en' => 'english',
'es' => 'spanish',
);
if (isset($_GET['lang']) && array_key_exists($_GET['lang'], $languages)) {
include './languages/' . $languages[$_GET['lang']] . '.php';
} else {
include './languages/english.php';
}
?>
5. Create a file called index.php
and fill the next lines in:
include_once 'includes/config.php';
echo $txt['headtext'];
?>
<form action="" method="get">
<select name="lang" size="1" onchange="this.form.submit();">
<option value="">Select your language...</option>
<option value="ro">Spanish</option>
<option value="en">English</option>
</select>
</form>
<a href="otherfile.php?lang=<?php echo $lang; ?>">otherfile.php</a>
6. That’s all. It’s really that simple. Just remember to refer to all links site wide as file.php?lang=<?php echo $lang; ?>
:
<a href="otherfile.php?lang=<?php echo $lang; ?>">otherfile.php</a>
1. First create a counter data file, we will call it counter.txt
.
2. Create the counter script, as follows:
counter.php
<div>Visitors:
<?php
$file = 'counter.txt';</code></p>
if (!file_exists($file)) {
$handle = fopen($file, 'w');
fwrite($handle, 0);
fclose($handle);
}
$count = file_get_contents($file);
$count++;
if (is_writable($file)) {
$handle = fopen($file, 'w+');
fwrite($handle, $count);
fclose($handle);
} else {
echo 'Unable to increment the counter!<br />';
}
echo number_format($count);
?>
</div>
3. That’s all. Remember to chmod
your data file – counter.txt
– to 777
. You can now include this script in your page with the following line:
<?php include 'counter.php'; ?>
Method 1.
This is the simplest way to list files in a folder:
<?php
$dir = '.';
$dh = opendir($dir);
while (($file = readdir($dh)) !== false) {
echo $file . '<br>';
}
closedir($dh);
?>
In order to add links to the files in the folder, we modify the code as below.
<?php
$dir = '.';
$dh = opendir($dir);
while (($file = readdir($dh)) !== false) {
echo '<a href="' . $file . '">' . $file . '</a><br>';
}
closedir($dh);
?>
Method 2.
Another way to read the files would be:
<?php
$dir = '.';
$dh = opendir($dir);
$count = 0;
while (($file = readdir($dh)) !== false) {
$count++;
if (substr($file, 0, 1) !== '.') {
echo $file . '<br>';
}
}
?>
The line if (substr($file, 0, 1) !== '.')
ensures that no .htaccess
or .htpasswd
file will be read.
Method 3.
The third method of reading and linking files in a directory would be:
<?php
$current = getcwd();
$directory = basename($current);
$dir = '.';
$dh = opendir($dir);
while (false !== ($filename = readdir($dh))) {
$files[] = $filename;
}
// Let's get rid of the '.' and the '..' parent and ancestor files
$t = array_slice($files, 2);
// Let's get rid of the index.php file which does the reading
$f = array_search('index.php', $t);
unset($t[$f]);
print('<a href=".">Back</a><br>');
foreach($t as $key => $value) {
echo('<a href="' . $value . '">' . $value . "</a><br>");
}
closedir($dh);
?>
Method 4.
The fourth method is the shortest of them all:
<?php
$dir = '.';
$files = scandir($dir);
//print_r($files);
$num = count($files);
for ($n=0; $n<$num; $n++) {
echo $files[$n] . '<br>';
}
?>
I left print_r($files);
in place but commented in order to show the directory array.
Method 5.
This method resembles phpMyAdmin’s way of listing files with an icon for folders and files. Further customization could show all file types, such as images, archives, php files, html files, css files, and so on. Notice how the ls_recursive()
function can be nicely tucked away in a functions file.
<?php
function ls_recursive2($dir) {
if (is_dir($dir)) {
$files = scandir($dir);
foreach ($files as $file) {
$currentfile = $dir . '/' . $file;
$last_dir = '';
$count = substr_count($currentfile, '/');
$minus_count = substr_count($_SERVER['DOCUMENT_ROOT'], '/');
$count -= ($minus_count + 2);
for($p = 0; $p<$count; $p++) {
$last_dir .= " ";
}
if (is_dir($currentfile)) {
if ($file != '.' && $file != '..') {
$last_dir .= "<img src='images/folder.gif' alt='' width='16' height='16'> <a href=\"" . $currentfile . "\">" . substr($currentfile, strrpos($currentfile, '/')) . "</a><br>";
echo $last_dir;
ls_recursive2($currentfile);
}
} else {
$last_dir .= "<img src='images/file.gif' alt='' width='16' height='16'> <a href=\"" . $currentfile . "\">" . substr($currentfile, strrpos($currentfile, '/')) . "</a><br>";
echo $last_dir;
}
}
}
}
ls_recursive2('.');
?>
Method 6.
Again a nice function for displaying both files in folders and files outside, a remake of the first method:
<?php
function listFolder($path) {
$dir_handle = opendir($path) or die("Unable to open $path");
$dirname = end(explode("/", $path));
echo ("<li>$dirname\n");
echo "<ul>\n";
while (false !== ($file = readdir($dir_handle))) {
if ($file!="." && $file!="..") {
if (is_dir($path."/".$file)) {
listFolder($path."/".$file);
} else {
echo "<li>$file</li>";
}
}
}
echo "</ul>\n";
echo "</li>\n";
closedir($dir_handle);
}
echo '<ul>';
listFolder('.');
echo '</ul>';
?>
Method 7.
Unlike the methods above, this one counts files of a certain extension (in this case, gifs):
<?php
$d = opendir('.');
$count = 0;
while (($f = readdir($d)) !== false)
if(ereg('.gif$', $f))
++$count;
closedir($d);
print "Files=$count";
?>
Method 8.
This method shows how many files (not folders) are in a directory:
<?php
function num_files($directory) {
return count(glob($directory."*.*"));
}
echo num_files('');
?>
Method 9.
The ninth method adds an interesting feature, file upload. While reading the files in a folder, the script has the capacity to upload a new file in the current directory.
<?php
if (isset($_POST['submit'])) {
copy($_FILES['file']['tmp_name'], $_FILES['file']['name']);
}
$dir=opendir(".");
$files=array();
while (($file=readdir($dir)) !== false) {
if($file != "." and $file != ".." and $file != "index.php") {
array_push($files, $file);
}
}
closedir($dir);
sort($files);
foreach ($files as $file)
print "<a href='$file'>$file</a><br />";
?>
<form action="" enctype="multipart/form-data" method="POST">
Add a new file: <input type="file" name="file">
<input type="submit" name="submit" value="Upload file">
</form>
That’s all!
Notice that all examples use '.'
, which means the current directory. By using '/'
these functions would scan the parent directory.
This is a basic affiliate system and it works by setting up a cookie and a database entry, and updating the record if a successful payment has gone through.
First of all, we need to detect if a link with an affiliate parameter has been clicked. So, we place the following code in the header of our template:
<?php
/**
* Custom affiliate conversion tracking code
*/
include WEBSITE_PATH . '/Affiliate.php';
if(isset($_GET['affid'])) {
// Get affiliate ID
$affid = filter_var(trim($_GET['affid']), FILTER_SANITIZE_NUMBER_INT);
affiliateGetVisit($affid);
}
if($url === '/payment-page') {
if(isset($_COOKIE['AffiliateURL'])) {
affiliateConvertVisit($_COOKIE['AffiliateID'], $_COOKIE['AffiliateURL'], $conversionValue, $transactionId, $transactionNumber);
}
}
Note that you will need to make some changes in order to accommodate the code above, namely the $url
variable, which holds the current page URL and the $conversionValue
, $transactionId
and $transactionNumber
variables, which hold details related to your own funnel system.
Next, we set up our Affiliate.php
file. This file holds lots of helper functions (device detection and database connection) and our main database insert and update routines.
<?php
/**
* Library for affiliate processing
*
* @copyright getButterfly.com 2016
*
*
* Add a parameter to any URL to test custom affiliate tracking
* $url .= (parse_url($url, PHP_URL_QUERY) ? '&' : '?') . 'affid=1';
*
*/
/**
* Get affiliate device (basic).
*
* @return string
*/
function clickIsMobile() {
return preg_match("/(android|webos|avantgo|iphone|ipad|ipod|blackberry|iemobile|bolt|bost|cricket|docomo|fone|hiptop|mini|opera mini|kitkat|mobi|palm|phone|pie|tablet|up\.browser|up\.link|webos|wos)/i", $_SERVER["HTTP_USER_AGENT"]);
}
/**
* Get affiliate device (extended).
*
* @return string
*/
function clickGetDevice() {
$userAgent = $_SERVER["HTTP_USER_AGENT"];
$devicesTypes = array(
"computer" => array("edge", "msie 11", "msie 10", "msie 9", "msie 8", "windows.*firefox", "windows.*chrome", "x11.*chrome", "x11.*firefox", "macintosh.*chrome", "macintosh.*firefox", "opera"),
"tablet" => array("tablet", "android", "ipad", "tablet.*firefox"),
"mobile" => array("mobile ", "android.*mobile", "iphone", "ipod", "opera mobi", "opera mini"),
"bot" => array("googlebot", "mediapartners-google", "adsbot-google", "duckduckbot", "msnbot", "bingbot", "ask", "facebook", "yahoo", "addthis")
);
foreach($devicesTypes as $deviceType => $devices) {
foreach($devices as $device) {
if(preg_match("/" . $device . "/i", $userAgent)) {
$deviceName = $deviceType;
}
}
}
return ucfirst($deviceName);
}
/**
* Get database connection.
*
* @return object
*/
function clickPdo() {
$db = new PDO('mysql:host=localhost;dbname=database;charset=utf8', 'user', 'password');
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
return $db;
}
/**
* Store affiliate visit details in log table.
*
* @param int $affiliateId
* @param string $target
* @return bool
*/
function affiliateGetVisit($affiliateId) {
$clickUrl = strtok("https://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]", '?');
$affiliateClickUrl = $affiliateClickUrl . '?affid=' . $affiliateId;
setcookie("AffiliateID", $affiliateId, strtotime('+30 days')); // 30 days
setcookie("AffiliateURL", $clickUrl, strtotime('+30 days')); // 30 days
$clickIp = $_SERVER['REMOTE_ADDR'];
$clickReferrer = $_SERVER['HTTP_REFERER'];
$clickTimestamp = date('Y-m-d H:i:s');
if(clickIsMobile()) {
$clickDevice = 'mobile';
} else {
$clickDevice = 'desktop';
}
$clickGetDevice = clickGetDevice();
$clickConversion = 0;
$clickTransactionId = 0;
$stmt = clickPdo()->prepare("INSERT INTO affiliate_log (
affiliateId,
clickReferrer,
clickTimestamp,
clickIp,
clickDevice,
clickUrl,
clickConversion,
clickTransactionId
) VALUES (
'$affiliateId',
'$clickReferrer',
'$clickTimestamp',
'$clickIp',
'$clickDevice ($clickGetDevice)',
'$clickUrl',
'$clickConversion',
'$clickTransactionId'
)");
$stmt->execute();
}
/**
* Update affiliate visit details in log table and remove all cookies. Sugar is bad.
*
* @param int $affiliateId
* @param string $affiliateUrl
* @param int $conversionValue
* @param int $transactionId
* @param string $transactionNumber
* @return bool
*/
function affiliateConvertVisit($affiliateId, $affiliateUrl, $conversionValue, $transactionId, $transactionNumber) {
$holidayUrl = strtok(urldecode($affiliateUrl), '?');
$clickIp = $_SERVER['REMOTE_ADDR'];
$stmt = clickPdo()->prepare("UPDATE affiliate_log SET
clickConversion = 1,
clickTransactionId = '$transactionId',
clickTransactionNo = '$transactionNumber',
clickTransactionValue = '$conversionValue'
WHERE
clickUrl = '$holidayUrl'
AND affiliateId = $affiliateId
AND clickIp = '$clickIp'
LIMIT 1");
$stmt->execute();
// Cookie has done its job, remove it
setcookie('AffiliateID', '', time() - 3600, '/');
unset($_COOKIE['AffiliateID']);
setcookie('AffiliateURL', '', time() - 3600, '/');
unset($_COOKIE['AffiliateURL']);
}
?>
This is my own approach and implementation. It’s basic and it needs more work, but it’s the first step if you want to code your own affiliate tracking system.
Thanks, this is very useful to me! I’ve been having some PHP problems with my gaming forum and I’ll check this out and see how it is!
Thank you very much for such a great article… i have been having some php problem for my gaming site … and i surely check this out.. ok
I think there is something wrong in the multilingual script.
The link fot otherfile.php doe not define the language.
It opens a window with url www.domain.com/otherfile.php?lang=
and doe not fill the selected lang.
Thank you in advance.
Hi Vrettos,
I read your comment and I tried the same with the same problem. Were you able to solve this problem of not showing the language code?
It’s been some time but I hope you remember…
Best regards…
I have been using this script successfully on some of my web sites. There must be something wrong with your server. Maybe global variables. Try < ? php echo $lang; ? > instead of < ? =$lang; ? >.
Where can i find more information about mod_gzip?
Do you know if i reduce the ft_min_word_len parameter may have some impact in the memory?
It may have some impact on memory but it will decrease your chances of success when searching.
And about mod_gzip:
http://schroepl.net/projekte/mod_gzip/config.htm
http://www.bluestream.org/Networking/gzip.htm
http://www.devarticles.com/c/a/Apache/Compressing-Web-Content-with-mod-gzip-and-mod-deflate/
I never knew point 29 on that list – really useful, as I do this a lot!
Thanks!
That’s super simple :) No verification of any kind anywhere. Is this good to directly use these variables without any escaping? This kind of code result into cross site scripting vulnerabilities (remember mikeyy on twitter?)
A couple of points you might want to consider:
1. You should include the USER-AGENT IP address in the email.
2.
This is just an example of contact form framework. Additional checks should be placed in the form.
You could place in you CSS stylesheet “img {border:0}”, without the quotes. Or add “border=”0″” inside the image tags, again without the quotes.
cool post, that was help me solve my problem, of course works perfectly for me! many thanks
.-= maxomen’s last blog ..SEO Indexed Search Engine =-.
hey thanks for sharing this. I have been having a little difficulty with a contact form so this might just come in handy :)
Hey, thanks for this php random image files
how do u use the include tag?
?
Warning: getimagesize(images/3.png) [function.getimagesize]: failed to open stream: No such file or directory in /home/content/s/i/m/simonshum/html/wp-content/themes/SR3/ads.php on line 15
It confuses me because that’s exactly where i put the php file.. Help? i’m doing this in wordpress
When i did this, it returned something like this :
Is the image too big? Is the path correct? What is on line 15?
i have the same problem than Chip. The line 15 is
list($img_width, $img_height) = getimagesize($random_img_url);
My pictures are 237×178
Thanks the scripts sounds good
Guys, I am using this script for random ads shown on several of my sites. I don’t have any problem with it. It seems that the array is not defined correctly. This code
$random_img_url = $array[$key]['img_url'];
extracts the images from the folder using url, alt and img_url keys.That’s why I’m asking if the path is correct, if the images exist and if you didn’t forgot a single-quote or something. Could you put the script online and point me to it? I’ll look in the source and tell you if anything is broken.
i carnt seem to get images to link parent _blank. any help
@jonathan: Why? What happens? Did you try changing line 16, and add
target="_blank"
?I got the script working on my site… it kept telling me the imagesize cannot be blank… so I removed that from script. How can I use this script to call up multiple images from the same random-ads.php script?
Thanks for feedback! The imagesize function issue could have been caused by some corrupt or unknown file format.
@Mike Wilday: this function calls the random image, right?
echo display_random_img($ads_array);
What you need to do is duplicate the $ads_array array – like $ads_array_1 – and call the function using your array:
echo display_random_img($ads_array);
echo display_random_img($ads_array_1);
echo display_random_img($ads_array_2);
Duplicate as many arrays as you want. Oh, and see the updated article :)
Will the multiple arrays avoid posting duplicate images? Or do I have to keep separate lists for each image? I’m hoping to create one list of images and links and then have the code call randomly from that one list, posting two images, but not the same ones. Any help?
Thanks for a great script. I’m also interested in adapting it so that it will check for duplicates. Right now I have 6 images, so I just put 3 in each array, but I’d like each array to pull from all 6, but avoid duplicating. Thanks!
Thank you Becki for using my script. Right now, you cannot do what you want. By having 2 arrays, you have 2 functions, so there’s no way of checking the current array item in both functions at the same time. I’d suggest you use 6 differrent images, so there’s no worry of duplicating.