Skip to content

Instantly share code, notes, and snippets.

@DigiLive
Last active February 14, 2023 08:41
Show Gist options
  • Save DigiLive/b061e070acefd062977549f813f27a72 to your computer and use it in GitHub Desktop.
Save DigiLive/b061e070acefd062977549f813f27a72 to your computer and use it in GitHub Desktop.
Collection of PHP functions.
<?php
/**
* Sort an array of rows.
*
* Sort an array of rows by column names.
* For each column to sort on, you pass two additional arguments to this function:
* 1 string as the columnName and 1 integer as the sorting flag.
*
* Pass the array, followed by the column names and sort flags:
* $sorted = arrayOrderby($dataArray, 'column1', SORT_DESC, 'column2', SORT_ASC);
*
* @author F. Cools - DigiLive
* @todo: Add Example.
*
* @param array $dataArray DataRows to be sorted.
* @return array Sorted data array.
*/
function arrayOrderby(array $dataArray) {
$arguments = func_get_args();
$dataArray = array_shift($arguments);
foreach ($arguments as $argumentKey => $argumentValue) {
if (is_string($argumentValue)) {
//Value is a string, so it's a columnName
$tempArray = [];
foreach ($dataArray as $key => $row) {
$tempArray[$key] = $row[$argumentValue];
}
$arguments[$argumentKey] = $tempArray;
}
}
$arguments[] = &$dataArray;
call_user_func_array('array_multisort', $arguments);
return array_pop($arguments);
}
/**
* Filter out array elements if the keyName doesn't start with a specific string.
*
* @param string $filter SubString to search.
* @param array $haystack Array to evaluate.
*
* @return array Filtered array.
*/
function filterKeys($filter, array $haystack) {
foreach (array_keys($haystack) as $keyName) {
if (substr($keyName, 0, strlen($filter)) != $filter) {
unset($haystack[$keyName]);
}
}
return $haystack;
}
/**
* Trim off the whitespace from the beginning and the end of each array element's value.
*
* If the element is a subarray, the values of this subarray are trimmed by calling this
* function recursively.
* The argument is supposed to be omitted to trim the values of the global POST variable.
* However it's possible to trim the values of a any array by passing it as an argument.
*
* @param array $array Array with values to trim.
*/
function trimPOST(array &$array = null) {
if (is_null($array)) {
$array = &$_POST;
}
foreach ($array as &$value) {
if (!is_array($value)) {
$value = trim($value);
} else {
trimPOST($value);
}
}
}
/**
* Strip html and php tags from each array element's value.
*
* If the element is a subarray, the values of this subarray are stripped by calling this
* function recursively.
* The argument is supposed to be omitted to strip the values of the global POST variable.
* However it's possible to strip the values of a any array by passing it as an argument.
*
* @param array $array Array with values to strip.
*/
function stripPOST($array = null) {
if (is_null($array)) {
$array = &$_POST;
}
foreach ($array as &$value) {
if (is_array($value)) {
stripPOST($value);
} else {
$value = strip_tags($value);
}
}
}
/**
* Checks existance of keys of an array.
*
* KeyNames can be wrapped in an array which is passed to the 2nd parameter
* or individual keyNames can be passed to the 2nd paramter and up.
*
* @param array $array Array to check for key existence.
* @param array|string $keys,... Array of keyNames or single keyNames.
*
* @return bool True when all keys exist in the array, False otherwise.
*/
function arrayKeysExist(array $array, $keys) {
$count = 0;
if (!is_array($keys) ) {
$keys = func_get_args();
array_shift($keys);
}
foreach ($keys as $key) {
if (array_key_exists($key, $array)) {
$count ++;
}
}
return count($keys) === $count;
}
/**
* Export a 2D data array to a csv file.
*
* Each element of the 2D data array is an array containing the row data.
* I.E. $dataArray[rowNumber][array of row data].
*
* Using the first element as a header: $dataArray[0] = array('ColTitle1', 'ColTitle2');
* Following elements as data: $dataArray[1] = array('ColData1', 'ColData1');
*
* The 2nd parameter specifies the output destionation of the file.
* When it's omitted or an empty string, the file is send to the output buffer.
* Otherwise a file, specified by the parameters value, on the file system.
*
* The 3th parameter specifies the separator of the csv fields.
* When ommitted, it defaults to a semicolon.
*
* Note:
* The 2nd parameter can't be omitted when specifying a separator.
* To send the file to the output buffer, specify the 2nd parameter as an empty string.
*
* @param array $data 2D data array containing elements of row data.
* @param string $toFile Optional: When a fileName is given, the data is written to this file, otherwise
* the data is written to the output buffer
* @param string $separator Optional: Character used to separate the values in the exported data. Default = ';'
* When defining a list separator, param $toFile must be '' when wanting to write to the output
* buffer
*
* @return bool true on succes, false otherwise
*/
function arrayToCsv(array $data, $toFile = '', $separator = ';') {
if (!is_string($toFile)) {
trigger_error('Paramater toFile is not of type string. Data is written to the output buffer!', E_USER_WARNING);
}
if ($toFile !== '') {
//Open filePointer
$output = fopen($toFile, 'w');
} else {
//Start Output Buffering
ob_start();
//Open Output Buffer
$output = fopen('php://output', 'w');
}
if ($output == false) {
//Output file or buffer can't be openened.
return false;
}
//Write records
foreach ($data as $record) {
if (fputcsv($output, $record, $separator) === false) {
echo 'Error writing data to output!';
}
}
//Close filePointer/Output Buffer
if (!fclose($output)) {
if ($toFile == '') {
$toFile = 'Output Buffer';
}
trigger_error("Error closing filepointer to '$toFile'", E_USER_NOTICE);
return false;
}
if ($toFile !== '') {
return true;
}
//Send headers to the browser to initiate download stream
header('Pragma: public');
header('Expires: -1');
header('Cache-Control: public, must-revalidate, post-check=0, pre-check=0');
header('Content-Disposition: attachment;filename="' . date(DATE_FORMAT . '_H-i-s') . '.csv"');
header('Content-Type: text/csv');
header('Content-Length: '.ob_get_length());
// Flush (send) the output buffer and turn off output buffering
ob_end_flush();
exit;
}
/**
* Get the lowest or highest value of a (multidimensional) array.
*
* Note:
* The order of low to high is defined the same as the order of php's (r)sort function.
*
* @param array $array Array containing the values to evaluate.
* @param boolean $min True to find the lowest value, False to find the highest.
* @return mixed Lowest or highest value in array.
*/
function arrayMinMax($array, $min = true) {
foreach($array as $key => $value) {
if (is_array($value)) {
$array[$key] = arrayMinMax($value, $min);
}
}
if ($min) {
rsort($array);
} else {
sort($array);
}
return array_pop($array);
}
/**
* Sum the values of an array, including the values in a sub array.
*
* @param array $array Array to sum the values for.
* @return number Sum of all (sub)array values.
*/
function sumRecursiveArrayValues(array $array) {
$total = 0;
foreach ($array as $value) {
if (is_array($value)) {
$total += sumRecursiveArrayValues($value);
} else {
$total += $value;
}
}
return $total;
}
/**
* Searches the array for a given value and returns the first corresponding key if successful.
*
* Notes:
* If needle is a string, the comparison is done in a case-sensitive manner.
*
* If the third parameter strict is set to true then the array_search() function will search for identical elements
* in the haystack. This means it will also perform a strict type comparison of the needle in the haystack, and
* objects must be the same instance.
*
* @param mixed $needle The searched value.
* @param array $haystack The array
* @param bool $strict If set to true, the function will search for identical elements.
*
* @return int|string|false The key of haystack where needle is found, false otherwise.
*/
public static function arraySearchRecursive($needle, array $haystack, bool $strict = false)
{
foreach ($haystack as $key => $value) {
$matchingValue = $strict ? $value === $needle : $value == $needle;
if ($matchingValue) {
return $key;
}
if (is_array($value) && self::arraySearchRecursive($needle, $value, $strict) !== false) {
return $key;
}
}
return false;
}
<?php
/**
* Auto Load Classes.
*
* Use to load classes when called by the application.
* Register this function to spl_autoload_register so you don't have to call this function manually.
*
* @param string $className Name of class to load.
* @throws RuntimeException When the class isn't accessible on the file system.
*/
function autoLoader($className) {
//Define project nameSpace prefix.
$prefix = '';
//Base directory for the nameSpace prefix
$baseDir = CLASS_DIR . '/';
//Does the class use the nameSpace prefix?
$prefixLength = strlen($prefix);
if (strncmp($prefix, $className, $prefixLength) !== 0) {
//No, move to the next registered autoloader
return;
}
//Get the relative className.
$relativeClassName = substr($className, $prefixLength);
/*
* Replace the namespace prefix by the base directory.
* Replace namespace separators by directory separators in the relative class name.
* append with the php file extension.
*/
$fileToLoad = $baseDir . str_replace('\\', DIRECTORY_SEPARATOR, $relativeClassName) . '.php';
//Require the file if it exists and can be read.
if (is_readable($fileToLoad)) {
require_once $fileToLoad;
} else {
throw new RuntimeException("The AutoLoader tried to require a file which doesn't exist! File: $fileToLoad");
}
}
<?php
/**
* Detect which field delimiter is used in a separated value file.
*
* The file is checked for the following delimiters: , tab ; | and :
*
* The 1st paramter defines the path to the file.
*
* The 2nd parameter defines how many lines to evaluate.
* To evaluate the complete file, make sure this number is at least as high as the number of rows in the file.
* When omitted, it defaults to 2.
*
* @param string $filePath Path to file to be analysed.
* @param number $checkLines Number of lines in file to analyse.
* @return string|boolean Character which is most likely used as a field delimiter or false on error.
*/
function getFieldDelimiter($filePath, $checkLines = 2){
try {
$filePath = new SplFileObject($filePath, 'r');
} catch (RuntimeException $e) {
return false;
}
$delimiters = array(',', '\t', ';', '|', ':');
$results = array();
$i = 0;
while($filePath->valid() && $i <= $checkLines){
$line = $filePath->fgets();
foreach ($delimiters as $delimiter){
$regExp = '/['.$delimiter.']/';
$fields = preg_split($regExp, $line);
if(count($fields) > 1){
if(!empty($results[$delimiter])){
$results[$delimiter]++;
} else {
$results[$delimiter] = 1;
}
}
}
$i++;
}
$results = array_keys($results, max($results));
if (empty($results)) {
return false;
} else {
return $results[0];
}
}
/**
* Detect which line terminators are used in a file.
*
* Note: Only the end of the first line is analysed for line terminators.
*
* @param string $filePath Path to file to be analysed.
* @return string|boolean Detected line terminators or false on error.
*/
function getLineTerminator($filePath) {
$autoDetect = ini_set('auto_detect_line_endings', true);
if (($handle = @fopen($filePath, 'r')) !== false) {
$line = fgets($handle);
fclose($handle);
$returnValue = preg_replace('/(*ANYCRLF)./', '', $line);
} else {
$returnValue = false;
}
ini_set('auto_detect_line_endings', $autoDetect);
return $returnValue;
}
/**
* Copy the contents of a folder to a new folder.
*
* SubFolders of the source folder will be copied as well.
* If the destination folder doesn't exist, it will be created.
*
* Warning:
* This function may return Boolean FALSE, but may also return a non-Boolean value which evaluates to FALSE.
* Please read the section on Booleans for more information. Use the === operator for testing the return value of this
* function.
*
* @param string $source Name of the source folder
* @param string $destination Name of the new folder
*
* @return bool|integer True on success, False on error. 0 when source directory doesn't exist.
*/
function copyFolder($source, $destination) {
$success = true;
$sourceFolder = @opendir($source);
if ($sourceFolder === false) {
return 0;
}
if (@mkdir($destination, 0777, true) === false) {
return false;
}
while (false !== ($file = readdir($sourceFolder))) {
if ($file === false) {
$success = false;
break;
}
if (($file != '.') && ($file != '..')) {
if (is_dir($source.'/'.$file)) {
copyFolder($source.'/'.$file, $destination.'/'.$file);
} else {
$success = copy($source.'/'.$file, $destination.'/'.$file);
}
}
}
closedir($sourceFolder);
return $success;
}
/**
* Create a zip archive file.
*
* The parameter should have an array as argument in the following format:
* array('fileName' => array(files of item))
*
* @param array $files FileName and filePaths.
* @return boolean False When the zip file couldn't be created or read afterwards.
*/
function createZip(array $files)
{
//Create a temporary zip file
$tempName = tempnam('tmp', '');
$zip = new ZipArchive();
$zip->open($tempName);
//Add files to the archive
foreach ($files as $itemName => $file) {
//Sanitize the name to match valid fileName format
$invalidChars = array(' ', '.', '/', '');
$itemName = str_replace($invalidChars, '_', $itemName);
$matches = [];
preg_match_all('/[^0-9^A-Z^a-z^_^.]/', $itemName, $matches);
foreach ($matches[0] as $value) {
$itemName = str_replace($value, '', $itemName);
}
$fileCount = count($file);
$i = 1;
if ($itemName == '') {
$itemName = $i;
}
foreach ($file as $fileName) {
$zip->addFile($fileName, $itemName.'_'.$i.'of'.$fileCount.'.'.pathinfo($fileName, PATHINFO_EXTENSION));
++$i;
}
//Close and reopen the zipfile to avoid passing the upper limit of simultaneously open files.
if ($i % 128 == 0) {
$zip->close();
$zip->open($tempName);
}
}
$zip->close();
//Sent the zip file to the output buffer
if (!is_file($tempName) || !is_readable($tempName)) {
return false;
} else {
header($_SERVER['SERVER_PROTOCOL'].' 200 OK');
header('Content-Type: application/zip');
header('Content-Transfer-Encoding: Binary');
header('Content-Length: '.filesize($tempName));
header('Content-Disposition: attachment; filename=export.zip');
readfile($tempName);
exit;
}
unlink($tempName);
}
/**
* Recursively delete a folder.
* The folder and its contents will be deleted.
*
* @param string $dirName Path to the folder.
* @return boolean True on success, False otherwise.
*/
function rRmDir($dirName) {
if (is_dir($dirName)) {
$objects = scandir($dirName);
foreach ($objects as $object) {
if ($object != "." && $object != "..") {
if (filetype($dirName . '/' . $object) == 'dir') {
rRmDir($dirName . '/' . $object);
} else {
unlink($dirName . '/' . $object);
}
}
}
reset($objects);
return rmdir($dirName);
}
return true;
}
<?php
/**
* Convert a integer number to its ordinal word presentation.
*
* When the argument is not a integer, this value is returned unchanged.
*
* @author F. Cools - DigiLive
*
* @param integer $integer Number to convert to ordinal word presentation
*
* @return string|mixed Ordinal word presentation the integer or original value.
*/
function IntToOrdinalWord($integer) {
if (!is_int($integer)) {
return $integer;
}
$firstWord = [
'eth',
'First',
'Second',
'Third',
'Fourth',
'Fifth',
'Sixth',
'Seventh',
'Eighth',
'Ninth',
'Tenth',
'Elevents',
'Twelfth',
'Thirteenth',
'Fourteenth',
'Fifteenth',
'Sixteenth',
'Seventeenth',
'Eighteenth',
'Nineteenth',
'Twentieth',
];
$secondWord = [
'',
'',
'Twenty',
'Thirthy',
'Forty',
'Fifty',
'Sixty',
'Seventy',
'Eighty',
'Ninety',
];
if ($integer <= 20) {
return $firstWord[$integer];
}
$firstNum = substr($integer, -1, 1);
$secondNum = substr($integer, -2, 1);
return str_replace('y-eth', 'ieth', $secondWord[$secondNum].'-'.$firstWord[$firstNum]);
}
Copyright (C) 2018 F. Cools
The code in this gist is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
The code in this gist is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this gist. If not, see <https://www.gnu.org/licenses/>.
========================================================================================================================
This is a collection of PHP functions which I've used in projects.
The code may be based on code from sources like stack overflow or any other (open) source I could find on the internet.
Please feel free to use this code.
<?php
/**
* Truncate a string to a maximum of characters.
*
* Note:
* The amount of returned characters may vary, but do not exceed the maximum value.
* This is because the returned string will always end in a complete word.
*
* @param string $string String to truncate.
* @param integer $length Max. number of characters.
* @return string Truncated string.
*/
function truncateString($string, $length) {
//Strip tags to avoid breaking any html
$string = strip_tags($string);
if (strlen($string) > $length) {
$stringCut = substr($string, 0, $length);
//Make it end in a word
$string = substr($stringCut, 0, strrpos($stringCut, ' ')).'&hellip;';
}
return $string;
}
/**
* Convert a camel-cased string to a snake-cased string.
*
* @param string $value Camel-cased string.
*
* @return string Snake-cased string.
*/
public static function camelToSnake(string $value): string
{
return strtolower(preg_replace('/(?<!^)[A-Z]/', '_$0', $value));
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment