Ok so basically I am reading through this piece of source code and do not understand the purpose of a specific area.
class URL_Processor
{
private static $urlPath;
private static $urlBits = array();
/*
Gets data from the current URL
#return Void
*/
public function getURLData()
{
$urldata = (isset($_GET['page'])) ? $_GET['page'] : '' ;
self::$urlPath = $urldata;
if( $urldata == '' )
{
self::$urlBits[] = 'home';
self::$urlPath = 'home';
}
else
{
$data = explode( '/', $urldata );
while ( !empty( $data ) && strlen( reset( $data ) ) === 0 )
{
array_shift( $data );
}
while ( !empty( $data ) && strlen( end( $data ) ) === 0)
{
array_pop($data);
}
self::$urlBits = $this->array_trim( $data );
}
}
private function array_trim( $array )
{
while ( ! empty( $array ) && strlen( reset( $array ) ) === 0)
{
array_shift( $array );
}
while ( !empty( $array ) && strlen( end( $array ) ) === 0)
{
array_pop( $array );
}
return $array;
}
}
So basically from my understanding the two while loops with 'array_shift' in the getURLData method empty out the array but according to my logic the second while loop wont even be able to empty anything out because the first while loop already did.
Then the last line of the method getURLData
self::$urlBits = $this->array_trim( $data );
does the same thing but how if the passed in argument is empty already?
Very confused!!!
The first while loop removes all leading elements in the array where their string length is zero, the second one does the same with trailing elements. reset($array) will point to the first, end($array) to the last element.
Why he mushes it through a second time? I don't know.
Related
I am facing the following problem. On my website I am trying to use a WordPress shortcode as input for a background color gradient.
The PHP is as follows:
function vip_relative_time() {
$post_date = get_the_time('U');
$delta = time() - $post_date;
$delta2 = intval(($delta/86400));
return $delta2;
}
add_shortcode('relativetime', 'vip_relative_time');
This code returns the amount of days that is between today and the post date. The goal is that the section on my website has a color gradient based on the above calculated days.
So when the calculating returns 50, 50% of the section will be filled with the selected color. This seems to work when I am editing the page:
But when I publish the page the the gradient is gone an I get the following error:
Warning
: Illegal string offset 'size' in
/home/customer/www/nicow23.sg-host.com/public_html/wp-content/plugins/elementor/includes/base/controls-stack.php
on line
1251
Anyone who can help me out to fix this problem? Do I maybe need to change the datatype of my shortcode?
Thanks in advance!
The code in controls-stack.php
/**
* Parse dynamic settings.
*
* Retrieve the settings with rendered dynamic tags.
*
* #since 2.0.0
* #access public
*
* #param array $settings Optional. The requested setting. Default is null.
* #param array $controls Optional. The controls array. Default is null.
* #param array $all_settings Optional. All the settings. Default is null.
*
* #return array The settings with rendered dynamic tags.
*/
public function parse_dynamic_settings( $settings, $controls = null, $all_settings = null ) {
if ( null === $all_settings ) {
$all_settings = $this->get_settings();
}
if ( null === $controls ) {
$controls = $this->get_controls();
}
foreach ( $controls as $control ) {
$control_name = $control['name'];
$control_obj = Plugin::$instance->controls_manager->get_control( $control['type'] );
if ( ! $control_obj instanceof Base_Data_Control ) {
continue;
}
if ( $control_obj instanceof Control_Repeater ) {
if ( ! isset( $settings[ $control_name ] ) ) {
continue;
}
foreach ( $settings[ $control_name ] as & $field ) {
$field = $this->parse_dynamic_settings( $field, $control['fields'], $field );
}
continue;
}
$dynamic_settings = $control_obj->get_settings( 'dynamic' );
if ( ! $dynamic_settings ) {
$dynamic_settings = [];
}
if ( ! empty( $control['dynamic'] ) ) {
$dynamic_settings = array_merge( $dynamic_settings, $control['dynamic'] );
}
if ( empty( $dynamic_settings ) || ! isset( $all_settings[ Manager::DYNAMIC_SETTING_KEY ][ $control_name ] ) ) {
continue;
}
if ( ! empty( $dynamic_settings['active'] ) && ! empty( $all_settings[ Manager::DYNAMIC_SETTING_KEY ][ $control_name ] ) ) {
$parsed_value = $control_obj->parse_tags( $all_settings[ Manager::DYNAMIC_SETTING_KEY ][ $control_name ], $dynamic_settings );
$dynamic_property = ! empty( $dynamic_settings['property'] ) ? $dynamic_settings['property'] : null;
if( is_array( $settings ) )
{
if ( $dynamic_property ) {
$settings[ $control_name ][ $dynamic_property ] = $parsed_value;
} else {
$settings[ $control_name ] = $parsed_value;
}
} else {
$settings[ $control_name ] = $parsed_value;
}
}
}
return $settings;
}
On or before line 1251, you should be checking if $settings is an array before trying to set its keys. If you do a var_dump($settings) prior to line 1251. It will probably tell you that it is not an array, and instead a string.
should be like this:
if( is_array( $settings ) )
{
//make sure we have an array first
if ( $dynamic_property ) {
$settings[ $control_name ][ $dynamic_property ] = $parsed_value;
} else {
$settings[ $control_name ] = $parsed_value;
}
} else {
//do something else
}
When I installed WooCommerce on a WordPress page I got the chance to manage a little while ago, I started getting these errors whenever I go to a subpage:
Warning: preg_match() [function.preg-match]: Compilation failed: nothing to ?repeat at offset 1 in /var/www/watertours.dk/public_html/wp-includes/class-wp.php on line 222
Warning: preg_match() [function.preg-match]: Compilation failed: nothing to repeat at offset 1 in /var/www/watertours.dk/public_html/wp-includes/class-wp.php on line 223"
It even shows up in the dashboard occasionally.
I have found this guide which I have already tried several times:
step 0: if possible, backup your WP installation folder.
step 1: temporary disable all the plugins (important step)
step 2: in WordPress admin dashboard, go to Settings -> Permalinks
step 3: remember or note down somewhere what you have in the custom permalinks field: http://awesomescreenshot.com/0534epzk0c 96
step 4: temporary enable (switch to) the default permalink: http://awesomescreenshot.com/0f74epyi15 79 Click Save Changes button.
step 5: verify the website is working now (not everything, because the plugins are disabled, but the preg_match error should be gone)
step 6: switch back to the custom permalinks setting you had at step 3
step 7: enable back all the plugins
The error should be gone."
It works for a little while (two minutes or so) and then those two errors start popping up again.
I am thinking of just remaking the WordPress site from the ground up since it is quite a mess anyway. But if anyone has a solution, I would be more than grateful. :)
EDIT:
* Parse request to find correct WordPress query.
*
* Sets up the query variables based on the request. There are also many
* filters and actions that can be used to further manipulate the result.
*
* #since 2.0.0
*
* #global WP_Rewrite $wp_rewrite
*
* #param array|string $extra_query_vars Set the extra query variables.
*/
public function parse_request( $extra_query_vars = '' ) {
global $wp_rewrite;
/**
* Filters whether to parse the request.
*
* #since 3.5.0
*
* #param bool $bool Whether or not to parse the request. Default true.
* #param WP $this Current WordPress environment instance.
* #param array|string $extra_query_vars Extra passed query variables.
*/
if ( ! apply_filters( 'do_parse_request', true, $this, $extra_query_vars ) ) {
return;
}
$this->query_vars = array();
$post_type_query_vars = array();
if ( is_array( $extra_query_vars ) ) {
$this->extra_query_vars = & $extra_query_vars;
} elseif ( ! empty( $extra_query_vars ) ) {
parse_str( $extra_query_vars, $this->extra_query_vars );
}
// Process PATH_INFO, REQUEST_URI, and 404 for permalinks.
// Fetch the rewrite rules.
$rewrite = $wp_rewrite->wp_rewrite_rules();
if ( ! empty( $rewrite ) ) {
// If we match a rewrite rule, this will be cleared.
$error = '404';
$this->did_permalink = true;
$pathinfo = isset( $_SERVER['PATH_INFO'] ) ? $_SERVER['PATH_INFO'] : '';
list( $pathinfo ) = explode( '?', $pathinfo );
$pathinfo = str_replace( '%', '%25', $pathinfo );
list( $req_uri ) = explode( '?', $_SERVER['REQUEST_URI'] );
$self = $_SERVER['PHP_SELF'];
$home_path = trim( parse_url( home_url(), PHP_URL_PATH ), '/' );
$home_path_regex = sprintf( '|^%s|i', preg_quote( $home_path, '|' ) );
// Trim path info from the end and the leading home path from the
// front. For path info requests, this leaves us with the requesting
// filename, if any. For 404 requests, this leaves us with the
// requested permalink.
$req_uri = str_replace( $pathinfo, '', $req_uri );
$req_uri = trim( $req_uri, '/' );
$req_uri = preg_replace( $home_path_regex, '', $req_uri );
$req_uri = trim( $req_uri, '/' );
$pathinfo = trim( $pathinfo, '/' );
$pathinfo = preg_replace( $home_path_regex, '', $pathinfo );
$pathinfo = trim( $pathinfo, '/' );
$self = trim( $self, '/' );
$self = preg_replace( $home_path_regex, '', $self );
$self = trim( $self, '/' );
// The requested permalink is in $pathinfo for path info requests and
// $req_uri for other requests.
if ( ! empty( $pathinfo ) && ! preg_match( '|^.*' . $wp_rewrite->index . '$|', $pathinfo ) ) {
$requested_path = $pathinfo;
} else {
// If the request uri is the index, blank it out so that we don't try to match it against a rule.
if ( $req_uri == $wp_rewrite->index ) {
$req_uri = '';
}
$requested_path = $req_uri;
}
$requested_file = $req_uri;
$this->request = $requested_path;
// Look for matches.
$request_match = $requested_path;
if ( empty( $request_match ) ) {
// An empty request could only match against ^$ regex
if ( isset( $rewrite['$'] ) ) {
$this->matched_rule = '$';
$query = $rewrite['$'];
$matches = array( '' );
}
} else {
foreach ( (array) $rewrite as $match => $query ) {
// If the requested file is the anchor of the match, prepend it to the path info.
if ( ! empty( $requested_file ) && strpos( $match, $requested_file ) === 0 && $requested_file != $requested_path ) {
$request_match = $requested_file . '/' . $requested_path;
}
if ( preg_match( "#^$match#", $request_match, $matches ) || // Line 222
preg_match( "#^$match#", urldecode( $request_match ), $matches ) ) { // Line 223
if ( $wp_rewrite->use_verbose_page_rules && preg_match( '/pagename=\$matches\[([0-9]+)\]/', $query, $varmatch ) ) {
// This is a verbose page match, let's check to be sure about it.
$page = get_page_by_path( $matches[ $varmatch[1] ] );
if ( ! $page ) {
continue;
}
$post_status_obj = get_post_status_object( $page->post_status );
if ( ! $post_status_obj->public && ! $post_status_obj->protected
&& ! $post_status_obj->private && $post_status_obj->exclude_from_search ) {
continue;
}
}
// Got a match.
$this->matched_rule = $match;
break;
}
}
}
if ( isset( $this->matched_rule ) ) {
// Trim the query of everything up to the '?'.
$query = preg_replace( '!^.+\?!', '', $query );
// Substitute the substring matches into the query.
$query = addslashes( WP_MatchesMapRegex::apply( $query, $matches ) );
$this->matched_query = $query;
// Parse the query.
parse_str( $query, $perma_query_vars );
// If we're processing a 404 request, clear the error var since we found something.
if ( '404' == $error ) {
unset( $error, $_GET['error'] );
}
}
// If req_uri is empty or if it is a request for ourself, unset error.
if ( empty( $requested_path ) || $requested_file == $self || strpos( $_SERVER['PHP_SELF'], 'wp-admin/' ) !== false ) {
unset( $error, $_GET['error'] );
if ( isset( $perma_query_vars ) && strpos( $_SERVER['PHP_SELF'], 'wp-admin/' ) !== false ) {
unset( $perma_query_vars );
}
$this->did_permalink = false;
}
}```
I´m trying from various paths to generate a dimensional array.
For that, I´m using the function found here.
My code
function get_dir_content_to_array( string $dir_path, string $dir_filter = null, string $file_filter = null ) {
if( is_dir_empty( $dir_path ) )
return false;
$output = array();
$files = get_subdir_filtered( $dir_path, $dir_filter, $file_filter );
if ( isset( $files ) ) {
foreach ( $files as $name => $object ) {
if ( $object->getFilename() !== "." && $object->getFilename() !== ".." ) {
// Split by the delimiter.
$delimiter = "/";
$name = str_replace( "\\", $delimiter, $name );
$relative_path = str_replace( $dir_path, "", $name );
$a_relative_path = explode( $delimiter, $relative_path );
$path = [ array_pop( $a_relative_path ) ];
foreach ( array_reverse( $a_relative_path ) as $pathPart ) {
$path = [ $pathPart => $path ];
}
// Add it to a temp list.
$paths[] = $path;
}
$output = call_user_func_array( 'array_merge_recursive', $paths );
}
}
return $output;
}
function get_subdir_filtered( $dir_path, $dir_filter, $file_filter ) {
$path = realpath( $dir_path );
$directory = new \RecursiveDirectoryIterator( $path );
$files = null;
if ( ! empty( $dir_filter ) || ! empty( $file_filter ) ) {
if ( ! empty( $dir_filter ) ) {
$filter = new DirnameFilter( $directory, $dir_filter );
}
if ( ! empty( $file_filter ) ) {
$filter = new FilenameFilter( $filter, $file_filter );
}
$files = new \RecursiveIteratorIterator( $filter );
} else {
$files = new \RecursiveIteratorIterator( $directory );
}
return $files;
}
class DirnameFilter extends FilesystemRegexFilter {
// Filter directories against the regex
public function accept() {
return ( ! $this->isDir() || preg_match( $this->regex, $this->getFilename() ) );
}
}
That works except when a folder is named "0"
How can I fixed that ?
Why array_pop skip the value "0" even if it´s a string ?
When json_encode() encodes an array whose keys are sequential integers starting from 0, or the string equivalents of them, it produces a JSON array rather than an object.
You could use the JSON_FORCE_OBJECT flag, but this will then turn the arrays of filenames inside a folder into objects, which you don't want.
What you can do is use a PHP object instead of an array to represent a folder. json_encode() will encode this as an object, even if it has numeric properties.
I think this might do it:
function get_dir_content_to_array( string $dir_path, string $dir_filter = null, string $file_filter = null ) {
if( is_dir_empty( $dir_path ) )
return false;
$output = array();
$files = get_subdir_filtered( $dir_path, $dir_filter, $file_filter );
if ( isset( $files ) ) {
foreach ( $files as $name => $object ) {
if ( $object->getFilename() !== "." && $object->getFilename() !== ".." ) {
// Split by the delimiter.
$delimiter = "/";
$name = str_replace( "\\", $delimiter, $name );
$relative_path = str_replace( $dir_path, "", $name );
$a_relative_path = explode( $delimiter, $relative_path );
$path = [ array_pop( $a_relative_path ) ];
foreach ( array_reverse( $a_relative_path ) as $pathPart ) {
$folder = new StdClass;
$folder->{$pathPart} = $path;
$path = $folder;
}
// Add it to a temp list.
$paths[] = $path;
}
$output = call_user_func_array( 'array_merge_recursive', $paths);
}
}
return $output;
}
I haven't tested it because I don't have the get_subdir_filtered() function. It's possible that array_merge_recursive won't do the correct merge of this. You might need to merge the objects, too. This tutorial contains an implementation of mergeObjectsRecursively that I think should be a useful substitute.
In my case I got this path : update.json and 0/1/0/filename.zip
As #Barmar said, basically, the problem is when I try to convert an array to a json object.
In PHP, an array is in fact, all the time an object so... $arr = [ "0" => [ "1" => ... ] ] for php, is equal to : $arr = [ 0 => [ 1 => ... ] ]. In PHP 7.2.x, each time you will merge objects, The "0" as string key will be cast to 0 as int.
Consequences
1 . with json_encode
echo json_encode( get_dir_content_to_array(...) );
//result = ["update.json",{"1":[["filename.zip"]]}]
2 . with json_encode and JSON_FORCE_OBJECT
echo json_encode( get_dir_content_to_array(...), JSON_FORCE_OBJECT );
//result = {"0":"update.json","1":{"1":{"0":{"0":"filename.zip"}}}}
//I got 1,0,0,filename.zip instead of 0,1,0,filename.zip
3 . Add (string)
$path = [array_pop( $a_relative_path)];
foreach ( array_reverse( $a_relative_path ) as $pathPart ) {
$path = [ (string) $pathPart => $path ];
}
//Same result of 2.
To keep the right order for the path, I found for the moment a hacky solution :
Add underscore before each key
foreach ( array_reverse( $a_relative_path ) as $pathPart ) {
$path = [ "_" . $a_relative_path => $path ];
}
//result = {"0":"update.json", "_0":{"_1":{"_0":{"0":"filenamezip"}}}}
//With a new file path, I got this :
// {"0":"update.json","_toto":{"_foo":{"0":"test.txt"}},"_0":{"_1":{"_0":{"0":"filename.zip"}}}}
This solution is a hack, but I can make a difference between a kee which is a path "_0":{"_1":{"_0" and a key to index a file "0":"filename.zip"
I have the following code:
$data = file_get_contents('http://www.robotevents.com/robot-competitions/vex-robotics-competition?limit=all');
echo "Downloaded";
$dom = new domDocument;
#$dom->loadHTML($data);
$dom->preserveWhiteSpace = false;
$tables = $dom->getElementsByTagName('table');
$rows = $tables->item(2)->getElementsByTagName('tr');
foreach ($rows as $row) {
$cols = $row->getElementsByTagName('td');
for ($i = 0; $i < $cols->length; $i++) {
echo $cols->item($i)->nodeValue . "\n";
}
}
The final field has an Link which I need to store the URL of. Also, The script outputs characters such as "Â". Does anyone know how to do/fix these things?
I would recommend not using DOM to parse HTML, as it has problems with invalid HTML. INstead use regular expression
I use this class:
<?php
/**
* Class to return HTML elements from a HTML document
* #version 0.3.1
*/
class HTMLQuery
{
protected $selfClosingTags = array( 'area', 'base', 'br', 'hr', 'img', 'input', 'link', 'meta', 'param' );
private $html;
function __construct( $html = false )
{
if( $html !== false )
$this->load( $html );
}
/**
* Load a HTML string
*/
public function load( $html )
{
$this->html = $html;
}
/**
* Returns elements from the HTML
*/
public function getElements( $element, $attribute_match = false, $value_match = false )
{
if( in_array( $element, $this->selfClosingTags ) )
preg_match_all( "/<$element *(.*)*\/>/isU", $this->html, $matches );
else
preg_match_all( "/<$element(.*)>(.*)<\/$element>/isU", $this->html, $matches );
if( $matches )
{
#Create an array of matched elements with attributes and content
foreach( $matches[0] as $key => $el )
{
$current_el = array( 'name' => $element );
$attributes = $this->parseAttributes( $matches[1][$key] );
if( $attributes )
$current_el['attributes'] = $attributes;
if( $matches[2][$key] )
$current_el['content'] = $matches[2][$key];
$elements[] = $current_el;
}
#Return only elements with a specific attribute and or value if specified
if( $attribute_match != false && $elements )
{
foreach( $elements as $el_key => $current_el )
{
if( $current_el['attributes'] )
{
foreach( $current_el['attributes'] as $att_name => $att_value )
{
$keep = false;
if( $att_name == $attribute_match )
{
$keep = true;
if( $value_match == false )
break;
}
if( $value_match && ( $att_value == $value_match ) )
{
$keep = true;
break;
}
elseif( $value_match && ( $att_value != $value_match ) )
$keep = false;
}
if( $keep == false )
unset( $elements[$el_key] );
}
else
unset( $elements[$el_key] );
}
}
}
if( $elements )
return array_values( $elements );
else
return array();
}
/**
* Return an associateive array of all the form inputs
*/
public function getFormValues()
{
$inputs = $this->getElements( 'input' );
$textareas = $this->getElements( 'textarea' );
$buttons = $this->getElements( 'button' );
$elements = array_merge( $inputs, $textareas, $buttons );
if( $elements )
{
foreach( $elements as $current_el )
{
$attribute_name = mb_strtolower( $current_el['attributes']['name'] );
if( in_array( $current_el['name'], array( 'input', 'button' ) ) )
{
if( isset( $current_el['attributes']['name'] ) && isset( $current_el['attributes']['value'] ) )
$form_values[$attribute_name] = $current_el['attributes']['value'];
}
else
{
if( isset( $current_el['attributes']['name'] ) && isset( $current_el['content'] ) )
$form_values[$attribute_name] = $current_el['content'];
}
}
}
return $form_values;
}
/**
* Parses attributes into an array
*/
private function parseAttributes( $str )
{
$str = trim( rtrim( trim( $str ), '/' ) );
if( $str )
{
preg_match_all( "/([^ =]+)\s*=\s*[\"'“”]{0,1}([^\"'“”]*)[\"'“”]{0,1}/i", $str, $matches );
if( $matches[1] )
{
foreach( $matches[1] as $key => $att )
{
$attribute_name = mb_strtolower( $att );
$attributes[$attribute_name] = $matches[2][$key];
}
}
}
return $attributes;
}
}
?>
Usage is:
$c = new HTMLQuery();
$x = $c->getElements( 'tr' );
print_r( $x );
I'm trying to get more advanced with php and I pick up the book PHP 5 Social Networking by Michael Peacock. While the book seemed to be interesting it didn't however get to involved in the details of the code. The function I'm trying to figure out is,
public function getURLData()
{
$urldata = ( isset( $_GET['page'] ) ) ? $_GET['page'] : '' ;
$this->urlPath = $urldata;
if( $urldata == '' )
{
$this->urlBits[] = '';
$this->urlPath = '';
}
else
{
$data = explode( '/', $urldata );
while ( !empty( $data ) && strlen( reset( $data ) ) === 0 )
{
//NOTES: php array_shift — Shift an element off the beginning of array
array_shift( $data );
}
while ( !empty( $data ) && strlen( end( $data ) ) === 0)
{
array_pop($data);
}
$this->urlBits = $this->array_trim( $data );
}
}
This a part of a larger class and the $_GET['page'] is something like this: relationships/mutual/3. My main question is what is happening in the else section. I think what is happening that it's removing any empty array indexes but I also question that.
Any help would be appreciated.
EDIT: added array_trim function that is also part of the class
private function array_trim( $array )
{
while ( ! empty( $array ) && strlen( reset( $array ) ) === 0)
{
array_shift( $array );
}
while ( !empty( $array ) && strlen( end( $array ) ) === 0)
{
array_pop( $array );
}
return $array;
}
public function getURLData()
{
Gets the 'page', this data can be obtained by $_GET from the url: for instance: http://mysite.com/?page=contact
If 'page' has been set, is assigned to $urldata, else $urldata=''
$urldata = ( isset( $_GET['page'] ) ) ? $_GET['page'] : '' ;
$this->urlPath = $urldata;
if( $urldata == '' )
{
$this->urlBits[] = '';
$this->urlPath = '';
}
else
{
Now is creating an array with all the substrings from $urldata splited by '/'
$data = explode( '/', $urldata );
If the array $data is not empty (otherwise accessing a non-existent element would raise an exception) or the lenght of the first element is equal to 0, then removes the first element from the array.
while ( !empty( $data ) && strlen( reset( $data ) ) === 0 )
{
//NOTES: php array_shift — Shift an element off the beginning of array
array_shift( $data );
}
If the array $data is not empty (otherwise accessing a non-existent element would raise an exception) or the lenght of the last element is equal to 0, then removes the last element from the array.
while ( !empty( $data ) && strlen( end( $data ) ) === 0)
{
array_pop($data);
}
array_trim is a custom function, not sure what does but probably will do some kind of trimming too
$this->urlBits = $this->array_trim( $data );
}
}