Skip to content

Instantly share code, notes, and snippets.

@earth3300
Last active October 8, 2018 23:50
Show Gist options
  • Select an option

  • Save earth3300/11d5f7f7e421363aef7c702412adc1c4 to your computer and use it in GitHub Desktop.

Select an option

Save earth3300/11d5f7f7e421363aef7c702412adc1c4 to your computer and use it in GitHub Desktop.
Converts JSON Color Data to HTML
<?php
/**
* EC01 JSON Index.
*
* Allows a JSON data text file to be viewed in a directory through a
* single index file.
*
* @package EC01 JSON Index
* @since 1.0.0
* @author Clarence Bos <cbos@tnoep.ca>
* @copyright Copyright (c) 2018, Clarence Bos
* @license https://www.gnu.org/licenses/gpl-3.0.en.html GPL-3.0+
* @link http://wp.cbos.ca/plugins/ec01-json-index
*
* @wordpress-plugin
* Plugin Name: EC01 JSON Index
* Plugin URI: http://wp.cbos.ca/plugins/ec01-json-index/
* Description: Allows a JSON data text file to be viewed in a directory through a single index file.
* Version: 1.0.0
* Author: Clarence Bos
* Author URI: http://ec01.earth3300.info/
* Text Domain: ec01-json-index
* License: GPL-3.0+
* License URI: https://www.gnu.org/licenses/gpl-3.0.en.html
*/
/**
* Allows a json file to be viewed in a directory.
*
* See the bottom of this file for a more complete description
* and the switch for determining the context in which this file
* is found.
*/
class JSONIndex
{
/** @var array Default options. */
protected $opts = [
'max' => 300,
'type' => 'json',
'msg' => [ 'na' => '', ],
];
/**
* Gets the JSON file as HTML.
*
* @param array $args
*
* @return string
*/
public function get( $args = null )
{
/** If no arguments are set, assume current directory */
if ( $args = $this->setDirectorySwitch( $args ) )
{
$max = $this->getMaxFiles( $args );
/** Add the "type" to the class string (i.e. json). */
$args['class'] = $this->opts['type'];
$str = '<article>' . PHP_EOL;
$args['type'] = $this->opts['type'];
if ( $match = $this->getMatchPattern( $args['type'], $args ) )
{
$str .= $this->iterateFiles( $match, $max, $args );
}
$str .= '</article>' . PHP_EOL;
if ( isset( $args['doctype'] ) && $args['doctype'] )
{
$str = $this->getPageHtml( $str, $args );
}
return $str;
}
else
{
return "Error.";
}
}
/**
* Iterate over files.
*
* Looks for json only.
*
* @param string $match
* @param array $args
*
* @return string
*/
private function iterateFiles( $match, $max, $args )
{
$str = '';
$cnt = 0;
foreach ( glob( $match ) as $file )
{
$cnt++;
if ( $cnt > $max )
{
break;
}
$args['file'] = $file;
/** Remove the root of the file path to use it a file source. */
$args['src'] = $this->getSrcFromFile( $args['file'] );
$args['name'] = $this->getNamefromFileName( $args['src'] );
if ( file_exists( $args['file'] ) )
{
$file = file_get_contents( $args['file'] );
$json = json_decode( $file );
}
$str .= $this->getHTMLfromJSON( $json );
}
return $str;
}
/**
* Get the source from the file, checking for a preceding slash.
*
* @param string $str
* @return string
*/
private function getSrcFromFile( $str )
{
$src = str_replace( $this->getSitePath(), '', $str );
/** May be server inconsistency, therefore remove and add again. */
$src = ltrim( $src, '/' );
return '/' . $src;
}
/**
* Get the SITE_PATH
*
* Get the SITE_PATH from the constant, from ABSPATH (if loading within WordPress
* as a plugin), else from the $_SERVER['DOCUMENT_ROOT']
*
* Both of these have been tested online to have a preceding forward slash.
* Therefore do not add one later.
*
* @return bool
*/
private function getSitePath()
{
if ( defined( 'SITE_PATH' ) )
{
return SITE_PATH;
}
/** Available if loading within WordPress as a plugin. */
elseif( defined( 'ABSPATH' ) )
{
return ABSPATH;
}
else
{
return $_SERVER['DOCUMENT_ROOT'];
}
}
/**
* Get the maximum number of images to process.
*
* @param array $args
* @return int
*/
private function getMaxFiles( $args )
{
if ( isset( $args['max'] ) )
{
$max = $args['max'];
}
else
{
$max = $this->opts['max'];
}
return $max;
}
/**
* Build the match string.
*
* This is iterated through for each type added to $types, above. A basic
* check for a reasonable string length (currently 10) is in place. Can
* develop this further, if needed.
*
* @param string $type 'jpg', 'png'
* @param array $args
*
* @return string|false
*/
private function getMatchPattern( $type, $args )
{
$path = $this->getBasePath( $args );
$prefix = "/*";
$match = $path . $prefix . $type;
/** Very basic check. Can improve, if needed. */
if ( strlen( $match ) > 10 )
{
return $match;
}
else {
return false;
}
}
/**
* Get the Base Path to the Media Directory.
*
* This does not need to include the `/media` directory.
*
* @param array $args
* @return string
*/
private function getBasePath( $args )
{
if ( isset( $args['self'] ) )
{
$path = __DIR__;
}
elseif ( defined( 'SITE_CDN_PATH' ) )
{
$path = SITE_CDN_PATH;
}
return $path;
}
/**
* Get the Media Directory
*
* @param array $args
*
* @return string
*
* @example $args['dir'] = '/architecture/shelter/micro-cabin/'
*/
private function getMediaDir( $args )
{
if ( isset( $args['dir'] ) )
{
$media = $args['dir'];
}
else
{
$media = '/media';
}
return $media;
}
/**
* Get the File HTML.
*
* Types: json
*
* @param array $args
*
* @return string
*/
private function getFileHtml( $args )
{
$str = '<div class="json">' . PHP_EOL;
$str .= sprintf( '<a href="%s">%s', $args['src'], PHP_EOL );
$str .= '<img';
$str .= sprintf( ' class="%s"', $this->getImageClass( $args ) );
$str .= sprintf( ' src="%s"', $args['src'] );
$str .= sprintf( ' alt="%s"', $this->getImageAlt( $args ) );
$str .= sprintf( ' width="%s"', $dim['width'] );
$str .= sprintf( ' height="%s"', $dim['height'] );
$str .= ' />' . PHP_EOL;
$str .= '</a>' . PHP_EOL;
$str .= '<p class="text-center">';
if ( $name = $this->getMediaName( $args['name'] ) )
{
$str .= sprintf( '<span class="name">%s</span>', $name );
}
if ( ! empty ( $dim['width'] && ! empty( $dim['height'] ) ) )
{
$str .= sprintf( ' <span class="dimensions">%sX%s</span>', $dim['width'], $dim['height'] );
}
if ( $size = $this->getMediaSize( $args ) )
{
$str .= sprintf( ' <span class="size">%s</span>', $size );
}
$str .= '</p>' . PHP_EOL;
$str .= '</div>' . PHP_EOL;
return $str;
}
/**
* Wrap the string in page HTML `<!DOCTYPE html>`, etc.
*
* @param string $str
* @return string
*/
public function getPageHtml( $html, $args )
{
$str = '<!DOCTYPE html>' . PHP_EOL;
$str .= sprintf( '<html class="dynamic %s" lang="en-CA">', $args['type'], PHP_EOL );
$str .= '<head>' . PHP_EOL;
$str .= '<meta charset="UTF-8">' . PHP_EOL;
$str .= '<meta name="viewport" content="width=device-width, initial-scale=1"/>' . PHP_EOL;
$str .= '<title>JSON Index</title>' . PHP_EOL;
$str .= '<meta name="robots" content="noindex,nofollow" />' . PHP_EOL;
$str .= '<link rel=stylesheet href="/0/theme/css/style.css">' . PHP_EOL;
$str .= '</head>' . PHP_EOL;
$str .= '<body>' . PHP_EOL;
$str .= '<main>' . PHP_EOL;
$str .= $html;
$str .= '</main>' . PHP_EOL;
$str .= '<footer>' . PHP_EOL;
$str .= '<div class="text-center"><small>';
$str .= 'Note: This page has been <a href="https://github.com/earth3300/ec01-json-index.git">automatically generated</a>. No header, footer, menus or sidebars are available.';
$str .= '</small></div>' . PHP_EOL;
$str .= '</footer>' . PHP_EOL;
$str .= '</html>' . PHP_EOL;
return $str;
}
/**
* Get the File Name from the String.
*
* Return the direct string values of each. Do no extra processing here.
*
* $regex = '/\/([a-z0-9\-]{3,150})\./'
*
* Part 1: Looks for letters, numbers and dashes from 3 to 150 characters.
* Part 2: Followed by a dash, then dimesions from 2 to 4 x 2 to 5 characters.
* Part 3: Ending. Followed by a dot \. (which will come before the extension).
*
* Not only does it divide the string given it into two parts, but it
* also does a basic quality check on the image name structure. If the image
* name does not meet the criteria given, it won't be captured.
*
* @param string $str
*
* @return array $arr['name']
*
* @example $arr['name'] = 'image-name'
*/
private function getImageNameDimArr( $str )
{
/**
* Since we won't have a valid image name with fewer than 13 characaters
* we won't bother processing anything with less than that length.
*/
if ( strlen( $str ) > 12 )
{
/** If this isn't matched, check for a name only */
$regex = '//\/([a-z0-9\-]{3,150})\./';
preg_match( $regex, $str, $match );
if ( empty( $match ) )
{
$regex = '/\/([a-z,0-9\-]{5,150})\./';
preg_match( $regex, $str, $match );
}
if ( ! empty( $match[1] ) )
{
$arr['name'] = $match[1];
}
else
{
$arr['name'] = null;
}
return $arr;
}
else {
return false;
}
}
/**
* Get the Name from the File Name
*
* @param array $args
*
* @return string
*/
private function getNamefromFileName( $str )
{
if ( strlen( $str ) > 2 )
{
$name = str_replace( '-', ' ', $str );
$name = strtoupper( $name );
}
else
{
$name = $this->opts['msg']['na'];
}
return $name;
}
/**
* Set the Directory Switch (Process Containing or Given Directory).
*
* If $args['self'] or $args['dir'] are not set, it assumes we are in the
* directory for which images are to be processed. Therefore $args['self']
* is set to true and $args['dir'] is set to null. We also have to set the
* $args['doctype'] to true to know whether or not to wrap the output in
* the correct doctype and the containing html and body elements.
*
* @param array $args
*
* @return array
*/
private function setDirectorySwitch( $args )
{
/** If $args['dir'] is not set, set it to false. */
$args['dir'] = isset( $args['dir'] ) ? $args['dir'] : false;
/** if $args['dir'] == false, set $args['self'] to true. */
if ( ! $args['dir'] )
{
$args['self'] = true;
$args['doctype'] = true;
return $args;
}
else
{
return $args;
}
}
/**
* JSON Color Data to HTML
*
* @param object $data JSON decoded file
*
* @return string
*
* @example echo jsonToTable([json-decoded-values]);
*
* @example echo jsonToTable(json_decode('{"name":"Bob","age":23,"skills":["php","javascript"]}'));
*/
private function getHTMLfromJSON($arr)
{
$str = '<div class="json" style="font-size: 80%;">' . PHP_EOL;
$max = $this->opts['max'];
$cnt = 0;
$str .= '<div class="line">' . PHP_EOL;
foreach ($arr as $key => $color)
{
$cnt++;
if( $cnt > $max ) {
break;
}
if( 0 ) {
echo "<pre>";
var_dump( $color->hsl );
echo "</pre>";
}
$str .= '<div class="unit size1of4" style="border-radius: 3px;">' . PHP_EOL;
$str .= '<div class="border" style="padding: 3px;">' . PHP_EOL;
$str .= '<div class="inner text-center" style="min-height: 46px; padding:6px; ' . PHP_EOL;
$str .= sprintf( 'background: %s;', $color->hexString );
$str .= sprintf( 'color: %s">', $this->getTextColor( $color->hsl ) );
$str .= sprintf('%s<br />%s', $color->name, PHP_EOL);
$str .= sprintf('%s%s<br />', $color->hexString, PHP_EOL);
$str .= sprintf('%s%s', $this->getHSLValue( $color->hsl ), PHP_EOL);
$str .= '</div>' . PHP_EOL;
$str .= '</div>' . PHP_EOL;
$str .= '</div>' . PHP_EOL;
}
$str .= '</div>' . PHP_EOL;
return $str;
}
/**
* Get the color of the text
*/
private function getTextColor( $hsl )
{
$value = $hsl->h + $hsl->s + $hsl->l;
if ( $value >= 250 ) {
$color = '#fff';
}
else {
$color = '#000';
}
return $color;
}
/**
* Get the HSL value as a String
*/
private function getHSLValue( $hsl )
{
$hsl = sprintf( '(%s, %s, %s)', number_format( $hsl->h, 0 ), $hsl->s, $hsl->l );
return $hsl;
}
}
/**
* Callback from the json-index shortcode.
*
* Performs a check, then instantiates the JSONIndex class
* and returns the results as HTML.
*
* @param array $args['dir']
* @return string HTML, wrapped in the article element.
*/
function json_index( $args )
{
if ( is_array( $args ) )
{
$media_index = new JSONIndex();
return $media_index -> get( $args );
}
else
{
return '<!-- Missing the directory to process. [json-index dir=""]-->';
}
}
/**
* Check context (WordPress Plugin File or Directory Index File).
*
* The following checks to see whether or not this file (index.php) is being loaded
* as part of the WordPress package, or not. If it is, we expect a WordPress
* function to be available (in this case, `add_shortcode`). We then ensure there
* is no direct access and add the shortcode hook, `media-index`. If we are not in
* WordPress, then this file acts as an "indexing" type of file by listing all
* of the allowed media types (currently jpg, png, mp3 and mp4) and making them
* viewable to the end user by wrapping them in HTML and making use of a css
* file that is expected to be found at `/0/media/theme/css/style.css`. This
* idea was developed out of work to find a more robust method to develop out a
* site, including that for a community. It makes use of the package found at:
* {@link https://github.com/earth3300/ec01/wiki/}, with the entire codeset
* available there through the same link.
*/
if( function_exists( 'add_shortcode' ) )
{
// No direct access.
defined('ABSPATH') || exit('No direct access.');
//shortcode [json-index dir=""]
add_shortcode( 'json-index', 'json_index' );
}
else
{
/**
* Outside of WordPress. Instantiate directly, assuming current directory.
*
* @return string
*/
$json_index = new JSONIndex();
echo $json_index -> get();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment