<?php
/**
* COPYRIGHT © 2022 JOHN PEARCEY
* All rights reserved
*/
const BASE64_DIGITS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz$_';
if (version_compare( PHP_VERSION, '8', '<') ){
include_once __DIR__ . "/common-pre-v8.php";
}
function getStackTrace(){
try{
throw new Exception;
}catch( Exception $e ){
return $e->getTraceAsString();
}
}
/**
* e.g. split
* ../db/stanhopetest/img/img_52548
* into
* [ ../db/stanhopetest/img/ , img_52548 ]
*
*/
function split_file_path( $ffn ){
$fn = basename( $ffn ); // img_52548
//$fp = substr( $ffn, 0, strlen($ffn) - strlen($fn) );
$fp = dirname( $ffn ) . '/';
return [ $fp, $fn ];
}
/**
* Returns true if it is possible to create this directory on the file system.
* Includes the possibility of multiple directories.
*/
function is_creatable_dir( $dirs ){
$dir = $dirs;
while(!file_exists($dir)){
$dir = dirname( $dir );
}
return is_writable($dir);
}
/**
* Function to make directories and actually SET the permissions
* https://www.php.net/manual/en/function.chmod.php
*
* $perms is an octal number
* e.g. mkdirs( $dir, 02770 ); //770 and g+s
*/
function mkdirs( $dirs, $perms ){
$dir = $dirs;
while(!file_exists($dir)){
$dir = dirname( $dir );
}
$rootDir = $dir;
if(!file_exists($dirs)) mkdir( $dirs, 0750, true ); //perms not always set
$dir = $dirs;
while( $dir!=$rootDir) {
chmod( $dir, $perms );
$dir = dirname( $dir );
}
}
/**
* Return the contents of a url as a string using the curl functions.
*/
function getContentsFromUrl( $url ){
$ch = curl_init( $url );
//$fp = fopen("example_homepage.txt", "w");
$fp = tmpfile();
curl_setopt($ch, CURLOPT_FILE, $fp);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
$c_err = curl_error($ch);
curl_close($ch);
if($c_err) {
error_log( $c_err );
fclose($fp);
return;
}
$f_path = stream_get_meta_data($fp)['uri'];
$rtn = file_get_contents( $f_path );
fclose($fp);
return $rtn;
}
/**
* Set the given key-value pair.
*
* Returns the record ID.
*/
function params_set( $key, $val ) {
$rec = R::findOne( 'params', 'pkey=?', [$key] );
if($rec) {
$rec->pval = $val;
R::store( $rec );
return $rec->id;
}
$rec = R::dispense( 'params' );
$rec->pkey = $key;
$rec->pval = $val;
return R::store( $rec );
}
function params_get_date( $key ){
return strtotime( params_get($key) );
}
/**
* Returns the value for the given key. Returns null if no such key exists.
*/
function params_get( $key ){
$rec = R::findOne( 'params', 'pkey=?', [$key] );
if(!$rec) return null;
return $rec->pval;
}
/**
* A novel way of creating a unique ID each time a call is made. The new ID is
* returned.
*
* e.g.
* This can be used to give a client which might want to create temporary unique IDs. It is
* called once per client refresh and used to ensure uniqueness of certain CSS data points.
*/
function params_unique( ) {
$rec = R::dispense( 'params' );
$rec->pkey = 'unique';
$id = R::store( $rec );
R::exec( "delete from params where id<$id and pkey='unique'" );
return $id;
}
/**
* Return a string representation for the given dom node suitable for debugging.
*/
function getNodeString( $rmElem ){
if($rmElem==null) return "Element is null";
$str="";
if( $rmElem->nodeType==XML_ELEMENT_NODE){
$str .= $rmElem->nodeName;
$a = $rmElem->getAttribute("shb_compid");
if($a){
$str .= " shb_compid=$a";
}
}else{
$str .= 'type = '.$rmElem->nodeType;
}
return $str;
}
/**
* Simple logger to write to a file. Using php error_log distorts all crlf pairs. This
* is a pain when you're trying to preserve them in html.
*/
function mylog( $msg ){
global $logging_on;
if(!$logging_on) return;
$p = __DIR__ . "/../../shb.log";
$h = fopen( $p, "a");
if($h===false) return;
fwrite( $h, "$msg\n");
fclose($h);
}
function generateNonce( $digitCount = 12 ){
// e.g. 422466a05f24b09c978fa1f6
return bin2hex( random_bytes($digitCount) );
}
/**
* Generate a randon username starting with a letter and containing only letters and numbers.
*/
function generateRndUserName( $digitCount = 10 ){
$l1 = generateRndStrUsing( 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', 1 );
return $l1 . generateRndStrUsing( BASE64_DIGITS, $digitCount-1 );
}
/**
* Generate a randon password with letters and numbers and some funny stuff.
*/
function generateRndPwd( $digitCount = 10 ){
return generateRndStrUsing( '0123456789_!"£$%^&*()_-|\?/<>#~ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz', $digitCount );
}
/**
* Generate a randon string of asc char. Default consisting of only [0-9][a-z][A-Z]
*/
function generateRndStrUsing( $using=BASE64_DIGITS, $digitCount = 8 ){
$str = '';
$maxlen = strlen($using);
for($i=0; $i<$digitCount; $i++){
$iv = random_int(0, $maxlen-1);
$str .= mb_substr( $using, $iv, 1); //use mb_substr because £ is not and asc char!
}
return $str;
}
/**
* Remove all html from the given string returning just the text content.
*/
function removeHtml( $str ){
//txt = txt.replace(/<div>/gi, '\n');
return preg_replace( '/<\/?[^>]+>/i', '', $str );
}
function getHtmlOkAsString( $data ){
$data = json_encode( $data );
return "[\"OK\", $data ]";
}
function sendHtmlOk( $data="" ){
echo getHtmlOkAsString( $data );
}
/**
* An effort to rectify my previously ill-thought out return encoding. You do not
* need to encode the data before calling this method. Any arrays will be json encoded.
*/
function sendHtmlOk_WithData( $data ){
$data = json_encode( $data );
echo "[\"OK\", $data ]";
}
function getHtmlErrorAsString( $strErrDesc = "--blank--" ){
$data = json_encode( $strErrDesc );
return "[\"Error\", $data]";
}
function sendHtmlError( $strErrDesc = "--blank--" ){
$rtn = getHtmlErrorAsString( $strErrDesc );
mylog( $rtn );
echo $rtn;
}
/**
*
*/
function getAttForPath( $name, $prefPath, $path){
return "$name = \"$prefPath/$path\"";
}
global $g_pub_path;
/**
* If the browser=true, the file returned will be correct for adding to an href or src attribute so that the
* browser will find the link.
*/
function getDirForType( $filetype='html', $browser=false, $userid=-1 ){
global $g_pub_path;
if($g_pub_path==null){
$g_pub_path = params_get('pub_path');
if($g_pub_path==null){
throw new Exception("Publishing now requires a valid key('pub_path') in the params table for the publishing output path");
}
if(str_ends_with( $g_pub_path, '/') ) $g_pub_path = substr($g_pub_path, 0, strlen($g_pub_path)-1 );
//ensure all the directories exist
createUserDir( 'img', $userid );
createUserDir( 'css', $userid );
createUserDir( 'html', $userid );
createUserDir( 'js', $userid );
}
return getDirForType_( $filetype, $browser, $userid );
}
function createUserDir( $dName, $userid ){
if(!file_exists(getDirForType_( $dName, false, $userid ))) {
$dir = getDirForType_( $dName, false, $userid );
error_log("common.php: createUserDir: $dir");
mkdir( $dir, 0770, true);
}
}
/**
* Part of the new path handling system is to sepatate out path names from real files
*/
function mkdirIfNotExists( $d ){
if(!file_exists( $d ) ) {
error_log("common.php: createUserDir: $d");
mkdir( $d, 0770, true );
}
}
/**
* For the moment, call getDirForType and not this function. In time, the setup routine will make the directories
* and eliminate the need for the check during a user session.
*
* If the browser flag is set, we assuming a document root sub-dir. But in time, this will need to also cater for
* a site serving the g_pub_path as root (wrt the browser).
*
*/
function getDirForType_( $filetype, $browser, $userid ){
global $g_pub_path;
$strPath = $g_pub_path;
if($userid>0){
$strPath .= "_dbg_$userid";
}
switch($filetype){
case 'img':
if($browser) return "/$strPath/img/";
return fxdPth( "$strPath/img/" );
case 'js':
if($browser) return "/$strPath/js/";
return fxdPth( "$strPath/js/" );
case 'css':
if($browser) return "/$strPath/css/";
return fxdPth( "$strPath/css/" );
case 'html':
default:
if($browser) return "/$strPath/";
return fxdPth( "$strPath/" );
}
}
//NO white-space