Automatic pass to convert with php-cs-fixer
This commit is contained in:
409
src/Console.php
409
src/Console.php
@@ -1,88 +1,103 @@
|
||||
<?php
|
||||
|
||||
/** DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
/**
|
||||
* DomFramework
|
||||
* @package domframework
|
||||
* @author Dominique Fournier <dominique@fournier38.fr>
|
||||
* @license BSD
|
||||
*/
|
||||
|
||||
namespace Domframework;
|
||||
|
||||
/** Allow to manage a linux Console to have a minimal but working text interface
|
||||
* When using this class, you must use the $console::echo method and not
|
||||
* display directely on screen
|
||||
* Like readline, but all in PHP
|
||||
* Manage the historical of the provided commands
|
||||
* Allow the user to use arrow keys and the shortcuts Ctrl+arrow, Ctrl+L,
|
||||
* Ctrl+U, Ctrl+W
|
||||
* To not allow the stop of the program by Ctrl+C, you can add
|
||||
* exec ("stty intr ^J");
|
||||
* To update the window size when the terminal is resized, use after console
|
||||
* instanciation :
|
||||
* declare(ticks = 1);
|
||||
* pcntl_signal (SIGWINCH, function () use ($console) {
|
||||
* $console->updateTerminalSize ();
|
||||
* });
|
||||
*/
|
||||
/**
|
||||
* Allow to manage a linux Console to have a minimal but working text interface
|
||||
* When using this class, you must use the $console::echo method and not
|
||||
* display directely on screen
|
||||
* Like readline, but all in PHP
|
||||
* Manage the historical of the provided commands
|
||||
* Allow the user to use arrow keys and the shortcuts Ctrl+arrow, Ctrl+L,
|
||||
* Ctrl+U, Ctrl+W
|
||||
* To not allow the stop of the program by Ctrl+C, you can add
|
||||
* exec ("stty intr ^J");
|
||||
* To update the window size when the terminal is resized, use after console
|
||||
* instanciation :
|
||||
* declare(ticks = 1);
|
||||
* pcntl_signal (SIGWINCH, function () use ($console) {
|
||||
* $console->updateTerminalSize ();
|
||||
* });
|
||||
*/
|
||||
class Console
|
||||
{
|
||||
// PROPERTIES
|
||||
/** Set the debug on if a filename is provided, or do not debug if false is
|
||||
* provided
|
||||
*/
|
||||
/**
|
||||
* Set the debug on if a filename is provided, or do not debug if false is
|
||||
* provided
|
||||
*/
|
||||
//private $debug = "/tmp/debug";
|
||||
private $debug = false;
|
||||
|
||||
/** Save the initial stty value
|
||||
*/
|
||||
/**
|
||||
* Save the initial stty value
|
||||
*/
|
||||
private $initSttyState;
|
||||
|
||||
/** Line Content
|
||||
*/
|
||||
/**
|
||||
* Line Content
|
||||
*/
|
||||
private $lineContent = "";
|
||||
|
||||
/** If true, display each char the user has pressed (echo mode)
|
||||
*/
|
||||
/**
|
||||
* If true, display each char the user has pressed (echo mode)
|
||||
*/
|
||||
private $echoMode = true;
|
||||
|
||||
/** List of non printable chars in decimal. The non printable chars are not
|
||||
* displayed but are correctely captured
|
||||
*/
|
||||
private $nonWriteableChar = array(1, 2, 3, 4, 6, 8, 9, 16, 18,
|
||||
/**
|
||||
* List of non printable chars in decimal. The non printable chars are not
|
||||
* displayed but are correctely captured
|
||||
*/
|
||||
private $nonWriteableChar = [1, 2, 3, 4, 6, 8, 9, 16, 18,
|
||||
20, 21, 22, 23, 24, 25, 27,
|
||||
127);
|
||||
127];
|
||||
|
||||
/** The history list in an array
|
||||
*/
|
||||
private $history = array();
|
||||
/**
|
||||
* The history list in an array
|
||||
*/
|
||||
private $history = [];
|
||||
|
||||
/** The history max size in entries
|
||||
*/
|
||||
/**
|
||||
* The history max size in entries
|
||||
*/
|
||||
private $historyMaxSize = 1000;
|
||||
|
||||
/** Set the completion keys. Not set by default
|
||||
*/
|
||||
/**
|
||||
* Set the completion keys. Not set by default
|
||||
*/
|
||||
private $completionKeys = false;
|
||||
|
||||
/** Set the function called when the completion char is called
|
||||
*/
|
||||
private $completionFunction = array();
|
||||
/**
|
||||
* Set the function called when the completion char is called
|
||||
*/
|
||||
private $completionFunction = [];
|
||||
|
||||
/** Set the width of the terminal in chars
|
||||
*/
|
||||
/**
|
||||
* Set the width of the terminal in chars
|
||||
*/
|
||||
private $termWidth;
|
||||
|
||||
/** Set the height of the terminal in chars
|
||||
*/
|
||||
/**
|
||||
* Set the height of the terminal in chars
|
||||
*/
|
||||
private $termHeight;
|
||||
|
||||
/** Store the last cursor position in the last readline
|
||||
*/
|
||||
/**
|
||||
* Store the last cursor position in the last readline
|
||||
*/
|
||||
private $cursorPos = 1;
|
||||
|
||||
/** The constructor init the console.
|
||||
* Check if we have the rights to execute, if wa have in cli...
|
||||
*/
|
||||
/**
|
||||
* The constructor init the console.
|
||||
* Check if we have the rights to execute, if wa have in cli...
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (! function_exists("exec")) {
|
||||
@@ -98,8 +113,9 @@ class Console
|
||||
$this->updateTerminalSize();
|
||||
}
|
||||
|
||||
/** Update the terminal size
|
||||
*/
|
||||
/**
|
||||
* Update the terminal size
|
||||
*/
|
||||
public function updateTerminalSize()
|
||||
{
|
||||
$this->termWidth = 80;
|
||||
@@ -120,8 +136,9 @@ class Console
|
||||
}
|
||||
}
|
||||
|
||||
/** The destructor return the terminal to initial state
|
||||
*/
|
||||
/**
|
||||
* The destructor return the terminal to initial state
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->initSttyState !== "") {
|
||||
@@ -132,51 +149,56 @@ class Console
|
||||
$this->textBold(false);
|
||||
}
|
||||
|
||||
/** Each time a key is pressed by the user, display the value on screen (echo)
|
||||
*/
|
||||
/**
|
||||
* Each time a key is pressed by the user, display the value on screen (echo)
|
||||
*/
|
||||
public function setEcho()
|
||||
{
|
||||
$this->echoMode = true;
|
||||
}
|
||||
|
||||
/** Each time a key is pressed by the user, DO NOT display the value on screen
|
||||
* (echo disabled)
|
||||
*/
|
||||
/**
|
||||
* Each time a key is pressed by the user, DO NOT display the value on screen
|
||||
* (echo disabled)
|
||||
*/
|
||||
public function unsetEcho()
|
||||
{
|
||||
$this->echoMode = false;
|
||||
}
|
||||
|
||||
/** Display a text on screen. Must be used before "readline" method because
|
||||
* the provided message will not be deleted by readline process.
|
||||
* @param string $message The message to display
|
||||
*/
|
||||
/**
|
||||
* Display a text on screen. Must be used before "readline" method because
|
||||
* the provided message will not be deleted by readline process.
|
||||
* @param string $message The message to display
|
||||
*/
|
||||
public function echo($message)
|
||||
{
|
||||
echo $message;
|
||||
$this->lineContent .= $message;
|
||||
}
|
||||
|
||||
/** Wait one valid character from the user.
|
||||
* The non printable chars are not displayed, nor returned
|
||||
* The ESC Sequences are skipped
|
||||
* @return the pressed char
|
||||
*/
|
||||
/**
|
||||
* Wait one valid character from the user.
|
||||
* The non printable chars are not displayed, nor returned
|
||||
* The ESC Sequences are skipped
|
||||
* @return the pressed char
|
||||
*/
|
||||
public function getc()
|
||||
{
|
||||
$char = $this->getKey();
|
||||
while (in_array(ord($char), $this->nonWriteableChar)) {
|
||||
while (in_array(ord($char), $this->nonWriteableChar, true)) {
|
||||
$char = $this->getKey();
|
||||
}
|
||||
return $char;
|
||||
}
|
||||
|
||||
/** Wait one key pressed by the user. If the key pressed is an ESC sequence,
|
||||
* return this sequence
|
||||
* The non printable chars are not displayed, but are correctely returned
|
||||
* The UTF8 chars are return as multiple length chars
|
||||
* @return the pressed char
|
||||
*/
|
||||
/**
|
||||
* Wait one key pressed by the user. If the key pressed is an ESC sequence,
|
||||
* return this sequence
|
||||
* The non printable chars are not displayed, but are correctely returned
|
||||
* The UTF8 chars are return as multiple length chars
|
||||
* @return the pressed char
|
||||
*/
|
||||
public function getKey()
|
||||
{
|
||||
$char = fgetc(STDIN);
|
||||
@@ -230,20 +252,21 @@ class Console
|
||||
// Four chars
|
||||
$char .= fgetc(STDIN) . fgetc(STDIN) . fgetc(STDIN);
|
||||
}
|
||||
if ($this->echoMode && ! in_array(ord($char), $this->nonWriteableChar)) {
|
||||
if ($this->echoMode && ! in_array(ord($char), $this->nonWriteableChar, true)) {
|
||||
echo $char;
|
||||
}
|
||||
return $char;
|
||||
}
|
||||
|
||||
/** Get the line of characters pressed by the user and return the result.
|
||||
* Stop when the user valid by \n.
|
||||
* Manage correctely the backspace, the Ctrl+W to remove word...
|
||||
* @param string $propo Preset the text for the user
|
||||
* @param boolean|string $stopperChar The chars to stop the analysis and
|
||||
* return the result
|
||||
* @return string The typed string
|
||||
*/
|
||||
/**
|
||||
* Get the line of characters pressed by the user and return the result.
|
||||
* Stop when the user valid by \n.
|
||||
* Manage correctely the backspace, the Ctrl+W to remove word...
|
||||
* @param string $propo Preset the text for the user
|
||||
* @param boolean|string $stopperChar The chars to stop the analysis and
|
||||
* return the result
|
||||
* @return string The typed string
|
||||
*/
|
||||
public function readline($propo = "", $stopperChar = false)
|
||||
{
|
||||
// Gets can not delete chars before the call. Keep the prompt (if exists)
|
||||
@@ -269,7 +292,7 @@ class Console
|
||||
}
|
||||
if (
|
||||
$stopperChar !== false &&
|
||||
in_array($char, $this->mb_str_split($stopperChar))
|
||||
in_array($char, $this->mb_str_split($stopperChar), true)
|
||||
) {
|
||||
// End of process with stopperChars
|
||||
$this->lineContent = "";
|
||||
@@ -277,7 +300,7 @@ class Console
|
||||
}
|
||||
if (
|
||||
$this->completionKeys !== false &&
|
||||
in_array($char, $this->mb_str_split($this->completionKeys))
|
||||
in_array($char, $this->mb_str_split($this->completionKeys), true)
|
||||
) {
|
||||
// Manage autocompletion
|
||||
$this->debug("Autocompletion starting");
|
||||
@@ -535,7 +558,7 @@ class Console
|
||||
$this->rewriteLine($prompt . $string);
|
||||
$this->moveCursor($cursorPos);
|
||||
}
|
||||
} elseif (in_array(ord($char), $this->nonWriteableChar)) {
|
||||
} elseif (in_array(ord($char), $this->nonWriteableChar, true)) {
|
||||
// Non writeable char : skip it
|
||||
$this->debug("Non writeable char : " . ord($char));
|
||||
} else {
|
||||
@@ -544,7 +567,7 @@ class Console
|
||||
$strArr = $this->mb_str_split($string);
|
||||
$firstArr = array_slice($strArr, 0, $cursorPos - $minLength);
|
||||
$lastArr = array_slice($strArr, $cursorPos - $minLength);
|
||||
$insertArr = array($char);
|
||||
$insertArr = [$char];
|
||||
$strArr = array_merge($firstArr, $insertArr, $lastArr);
|
||||
$string = implode($strArr);
|
||||
$cursorPos++;
|
||||
@@ -556,10 +579,11 @@ class Console
|
||||
return $string;
|
||||
}
|
||||
|
||||
/** Rewrite the line with the provided $text.
|
||||
* Delete all the old data
|
||||
* @param string $text The new text to use on line
|
||||
*/
|
||||
/**
|
||||
* Rewrite the line with the provided $text.
|
||||
* Delete all the old data
|
||||
* @param string $text The new text to use on line
|
||||
*/
|
||||
private function rewriteLine($text)
|
||||
{
|
||||
$this->debug("Call rewriteLine ($text)");
|
||||
@@ -571,9 +595,10 @@ class Console
|
||||
}
|
||||
}
|
||||
|
||||
/** Move the cursor on position $position. The first column is $cursorPos=1
|
||||
* @param integer $cursorPos The new position on line
|
||||
*/
|
||||
/**
|
||||
* Move the cursor on position $position. The first column is $cursorPos=1
|
||||
* @param integer $cursorPos The new position on line
|
||||
*/
|
||||
private function moveCursor($cursorPos)
|
||||
{
|
||||
$this->debug("Call moveCursor ($cursorPos)");
|
||||
@@ -602,8 +627,9 @@ class Console
|
||||
}
|
||||
}
|
||||
|
||||
/** Clear the existing line.
|
||||
*/
|
||||
/**
|
||||
* Clear the existing line.
|
||||
*/
|
||||
public function clearLine()
|
||||
{
|
||||
$this->debug("Call clearLine");
|
||||
@@ -631,37 +657,41 @@ class Console
|
||||
$this->cursorPos = 1;
|
||||
}
|
||||
|
||||
/** Clear all the screen and remove the scroll of the screen
|
||||
*/
|
||||
/**
|
||||
* Clear all the screen and remove the scroll of the screen
|
||||
*/
|
||||
public function clearScreen()
|
||||
{
|
||||
echo "\033[2J\033[;H\033c";
|
||||
}
|
||||
|
||||
/** Get the terminal Height
|
||||
*/
|
||||
/**
|
||||
* Get the terminal Height
|
||||
*/
|
||||
public function getTermHeight()
|
||||
{
|
||||
return $this->termHeight;
|
||||
}
|
||||
|
||||
/** Get the terminal Width
|
||||
*/
|
||||
/**
|
||||
* Get the terminal Width
|
||||
*/
|
||||
public function getTermWidth()
|
||||
{
|
||||
return $this->termWidth;
|
||||
}
|
||||
|
||||
/** Call a specific function when a completion key is pressed
|
||||
* The function must get the partial text as first parameter, and must return
|
||||
* an array with the possibilities
|
||||
* If only one possibility is returned, the console will be immediately
|
||||
* updated.
|
||||
* @param string|bool $completionKeys The list of the completion keys. False
|
||||
* unset the method
|
||||
* @param callable $completionFunction The function called when one of the
|
||||
* completion keys is pressed.
|
||||
*/
|
||||
/**
|
||||
* Call a specific function when a completion key is pressed
|
||||
* The function must get the partial text as first parameter, and must return
|
||||
* an array with the possibilities
|
||||
* If only one possibility is returned, the console will be immediately
|
||||
* updated.
|
||||
* @param string|bool $completionKeys The list of the completion keys. False
|
||||
* unset the method
|
||||
* @param callable $completionFunction The function called when one of the
|
||||
* completion keys is pressed.
|
||||
*/
|
||||
public function completeFunction($completionKeys, $completionFunction)
|
||||
{
|
||||
if (! is_string($completionKeys) && ! is_boolean($completionKeys)) {
|
||||
@@ -678,25 +708,28 @@ class Console
|
||||
$this->completionFunction = $completionFunction;
|
||||
}
|
||||
|
||||
/** Get the actual history in memory
|
||||
*/
|
||||
/**
|
||||
* Get the actual history in memory
|
||||
*/
|
||||
public function getHistory()
|
||||
{
|
||||
return $this->history;
|
||||
}
|
||||
|
||||
/** Clear the history
|
||||
* This method do NOT write the empty history on disk
|
||||
*/
|
||||
/**
|
||||
* Clear the history
|
||||
* This method do NOT write the empty history on disk
|
||||
*/
|
||||
public function clearHistory()
|
||||
{
|
||||
$this->history = array();
|
||||
$this->history = [];
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Write the history to disk.
|
||||
* @param string $historyFile The history file where the history is stored
|
||||
*/
|
||||
/**
|
||||
* Write the history to disk.
|
||||
* @param string $historyFile The history file where the history is stored
|
||||
*/
|
||||
public function writeHistory($historyFile)
|
||||
{
|
||||
if (file_exists($historyFile)) {
|
||||
@@ -729,16 +762,17 @@ class Console
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Read the history from the disk
|
||||
* If the file doesn't exists, return an empty array
|
||||
* @param string $historyFile The history file where the history is stored
|
||||
* @return the read history with timestamp as key and command as value
|
||||
*/
|
||||
/**
|
||||
* Read the history from the disk
|
||||
* If the file doesn't exists, return an empty array
|
||||
* @param string $historyFile The history file where the history is stored
|
||||
* @return the read history with timestamp as key and command as value
|
||||
*/
|
||||
public function readHistory($historyFile)
|
||||
{
|
||||
if (! file_exists($historyFile)) {
|
||||
$this->history = array();
|
||||
return array();
|
||||
$this->history = [];
|
||||
return [];
|
||||
}
|
||||
if (! is_readable($historyFile)) {
|
||||
$this->consoleException("History file '$historyFile' can not be read");
|
||||
@@ -765,11 +799,12 @@ class Console
|
||||
return $this->history;
|
||||
}
|
||||
|
||||
/** Add a new entry in history.
|
||||
* The new line can not be empty : it is not stored, but without error
|
||||
* This method do NOT write the history on disk : you must use writeHistory
|
||||
* @param string The new entry to add in history
|
||||
*/
|
||||
/**
|
||||
* Add a new entry in history.
|
||||
* The new line can not be empty : it is not stored, but without error
|
||||
* This method do NOT write the history on disk : you must use writeHistory
|
||||
* @param string The new entry to add in history
|
||||
*/
|
||||
public function addHistory($line)
|
||||
{
|
||||
if (! is_string($line)) {
|
||||
@@ -789,10 +824,11 @@ class Console
|
||||
return $this;
|
||||
}
|
||||
|
||||
/** Get/Set the maximum number of entries in the history
|
||||
* If null, get the defined maximum number
|
||||
* @param integer|null $historyMaxSize The maximum number of entries
|
||||
*/
|
||||
/**
|
||||
* Get/Set the maximum number of entries in the history
|
||||
* If null, get the defined maximum number
|
||||
* @param integer|null $historyMaxSize The maximum number of entries
|
||||
*/
|
||||
public function historyMaxSize($historyMaxSize = null)
|
||||
{
|
||||
if ($historyMaxSize === null) {
|
||||
@@ -805,17 +841,19 @@ class Console
|
||||
$this->historyMaxSize = intval($historyMaxSize);
|
||||
}
|
||||
|
||||
/** Error management
|
||||
* @param string $message The message to throw in the exception
|
||||
*/
|
||||
/**
|
||||
* Error management
|
||||
* @param string $message The message to throw in the exception
|
||||
*/
|
||||
public function consoleException($message)
|
||||
{
|
||||
throw new \Exception($message, 500);
|
||||
}
|
||||
|
||||
/** Set the text color
|
||||
* @param integer $colorNum The color number to use
|
||||
*/
|
||||
/**
|
||||
* Set the text color
|
||||
* @param integer $colorNum The color number to use
|
||||
*/
|
||||
public function colorText($colorNum)
|
||||
{
|
||||
if (! is_int($colorNum)) {
|
||||
@@ -825,9 +863,10 @@ class Console
|
||||
echo "\033[38;5;{$colorNum}m";
|
||||
}
|
||||
|
||||
/** Set the background text color
|
||||
* @param integer $colorNum The color number to use
|
||||
*/
|
||||
/**
|
||||
* Set the background text color
|
||||
* @param integer $colorNum The color number to use
|
||||
*/
|
||||
public function colorBackgroundText($colorNum)
|
||||
{
|
||||
if (! is_int($colorNum)) {
|
||||
@@ -837,16 +876,18 @@ class Console
|
||||
echo "\033[48;5;{$colorNum}m";
|
||||
}
|
||||
|
||||
/** Reset the colors
|
||||
*/
|
||||
/**
|
||||
* Reset the colors
|
||||
*/
|
||||
public function colorReset()
|
||||
{
|
||||
echo "\033[0m";
|
||||
}
|
||||
|
||||
/** Underline the text
|
||||
* @param boolean $underline True to underline, false to remove the underline
|
||||
*/
|
||||
/**
|
||||
* Underline the text
|
||||
* @param boolean $underline True to underline, false to remove the underline
|
||||
*/
|
||||
public function textUnderline($underline)
|
||||
{
|
||||
if ($underline === false) {
|
||||
@@ -857,9 +898,10 @@ class Console
|
||||
echo "\033[{$underline}4m";
|
||||
}
|
||||
|
||||
/** Bold the text
|
||||
* @param boolean $bold True to bold, false to remove the bold
|
||||
*/
|
||||
/**
|
||||
* Bold the text
|
||||
* @param boolean $bold True to bold, false to remove the bold
|
||||
*/
|
||||
public function textBold($bold)
|
||||
{
|
||||
if ($bold === false) {
|
||||
@@ -870,22 +912,24 @@ class Console
|
||||
echo "\033[{$bold}m";
|
||||
}
|
||||
|
||||
/** Return true if the TTY is enabled, or false if the program is called from pipe
|
||||
*/
|
||||
/**
|
||||
* Return true if the TTY is enabled, or false if the program is called from pipe
|
||||
*/
|
||||
public function isTTY()
|
||||
{
|
||||
return !! $this->initSttyState;
|
||||
}
|
||||
|
||||
/** Tokenize the provided line and aggragate if there is single or double
|
||||
* quotes.
|
||||
* Trim the spaces
|
||||
* @param string $line The line to tokenize
|
||||
* @return array The tokens
|
||||
*/
|
||||
/**
|
||||
* Tokenize the provided line and aggragate if there is single or double
|
||||
* quotes.
|
||||
* Trim the spaces
|
||||
* @param string $line The line to tokenize
|
||||
* @return array The tokens
|
||||
*/
|
||||
public static function tokenize($line)
|
||||
{
|
||||
$tokens = array();
|
||||
$tokens = [];
|
||||
$token = strtok(trim($line), ' ');
|
||||
while ($token) {
|
||||
// find double quoted tokens
|
||||
@@ -902,23 +946,25 @@ class Console
|
||||
return $tokens;
|
||||
}
|
||||
|
||||
/** This function return an array with each char, but supports UTF-8
|
||||
* @param string $string The string to explode
|
||||
* @param integer $split_length The number of chars in each split
|
||||
* @return array
|
||||
*/
|
||||
/**
|
||||
* This function return an array with each char, but supports UTF-8
|
||||
* @param string $string The string to explode
|
||||
* @param integer $split_length The number of chars in each split
|
||||
* @return array
|
||||
*/
|
||||
private function mb_str_split($string, $split_length = 1)
|
||||
{
|
||||
$res = array();
|
||||
$res = [];
|
||||
for ($i = 0; $i < mb_strlen($string); $i += $split_length) {
|
||||
$res[] = mb_substr($string, $i, $split_length);
|
||||
}
|
||||
return $res;
|
||||
}
|
||||
|
||||
/** This function debug the data
|
||||
* @param mixed $data The data to store
|
||||
*/
|
||||
/**
|
||||
* This function debug the data
|
||||
* @param mixed $data The data to store
|
||||
*/
|
||||
private function debug($data)
|
||||
{
|
||||
if ($this->debug === false) {
|
||||
@@ -930,10 +976,11 @@ class Console
|
||||
file_put_contents($this->debug, date("H:i:s") . " $data\n", FILE_APPEND);
|
||||
}
|
||||
|
||||
/** Look in the array which first chars of each possibilites are identical.
|
||||
* @param array $completeArr The values to examine
|
||||
* @return string the identical chars
|
||||
*/
|
||||
/**
|
||||
* Look in the array which first chars of each possibilites are identical.
|
||||
* @param array $completeArr The values to examine
|
||||
* @return string the identical chars
|
||||
*/
|
||||
private function shortestIdenticalValues($completeArr)
|
||||
{
|
||||
if (! is_array($completeArr)) {
|
||||
|
||||
Reference in New Issue
Block a user