Skip to content

Instantly share code, notes, and snippets.

@earth3300
Created November 3, 2019 21:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save earth3300/5763a0157f145d3f8649160741d1da3a to your computer and use it in GitHub Desktop.
Save earth3300/5763a0157f145d3f8649160741d1da3a to your computer and use it in GitHub Desktop.
Creates a CSV file based on loaded images.
<?php
/**
* EC01 CSV Printer (Images)
*
* Creates a CSV file from images. This CSV file can be imported into a
* database such as that used by WooCommerce and used in an online shop.
*
* @package Earth3300\EC01
* @since 1.0.1
* @author Clarence J. Bos <cbos@tnoep.ca>
* @copyright Copyright (c) 2018, Clarence J. Bos
* @license https://www.gnu.org/licenses/gpl-3.0.en.html GPL v3.0
* @link https://github.com/earth3300/ec01-csv-printer
*
* File: printer.csv.php
* Created: 2018------
* Updated: 2019-11-03
* Time: 10:49 EDT
*/
namespace Earth3300\EC01;
/**
* Prints a CSV file.
*/
class CsvPrinter
{
/** @var array Default options. */
protected $opts = [
'page' => [
'title' => 'CSV Printer',
],
'date' => [
'created' => '2019-07-17'
],
'dir' => [
'input' => '/0/m/shop/2019/09/src',
'output' => '/0/m/shop/2019/09/csv',
],
'file' => [
'type' => '.{jpg,png}',
'output' => [
'csv' => '/products.csv',
],
],
'max' => [
'files' => 50, // When picking up...
'length' => 3000000, // No more than 3MB please... :}
'cnt' => 40, // When putting together...
],
'site' => [
'url' => 'http://wp00p.earth3300.local',
],
'media' => [
'dir' => '/0/m',
],
'shop' => [
'dir' => '/shop'
],
'product' => [
'dir' => '/product',
],
'category' => 'nature',
'message' => [
'na' => 'Not available.',
'write' => [
'denied' => 'Write permission denied.' ,
'success' => 'Write operation succeeded.',
'failure' => 'Write operation failed.',
],
],
];
/**
* Init
*/
public function init()
{
if( $this->security() )
{
if( $this->environment() )
{
if( $this->authorize() )
{
$this->run();
}
}
}
}
/**
* Security
*
* @return bool
*/
private function security()
{
if ( file_exists( __DIR__ . '/.security' ) )
{
return true;
}
else
{
return false;
}
}
/**
* Environment
*
* @return bool
*/
private function environment()
{
if ( '127.0.0.1' == $_SERVER['REMOTE_ADDR'] )
{
return true;
}
else
{
return false;
}
}
/**
* Authorize
*
* @return bool
*/
private function authorize()
{
if( isset( $_GET['unlock'] ) )
{
return true;
}
else
{
return false;
}
}
/**
* Run
*
* @return string|mixed
*/
private function run()
{
// Initialize.
$files = [];
if( isset( $_POST['safety'] ) )
{
$files['path'] = $this->getPaths();
$files['text'] = $this->getFileDesc();
$files = $this->getFileNames( $files );
$files = $this->getFilesData( $files );
$files = $this->getCsvData( $files );
$files['resp'] = $this->putContents( $files );
$files['msg'] = $this->getMessage( $files );
}
$html = $this->getPageHTML( $files );
echo $html;
}
/**
* Get the Paths to the Files to Process.
*
* @return array
*/
private function getPaths()
{
$path = [];
$path['root'] = rtrim( $_SERVER['DOCUMENT_ROOT'], '/' );
$path['input'] = $path['root'];
$path['input'] .= $this->opts['dir']['input'];
$path['output'] = $path['root'];
$path['output'] .= $this->opts['dir']['output'];
$path['file']['output'] = $path['output'];
$path['file']['output'] .= $this->opts['file']['output']['csv'];
return $path;
}
/**
* The Page HTML
*/
private function thePageHtml( $html )
{
echo $html;
}
/**
* Get File Names
*
* Get file names via "glob" and exclusion or a preconstructed list. Includes
* a check to ensure no more than the maximum number of files are returned.
*
* @return array
*/
private function getFileNames( $files )
{
// Initialize.
$files['data'] = null;
$match = $files['path']['input'] . '/*' . $this->opts['file']['type'];
$items = glob( $match, GLOB_BRACE );
if( is_array( $items ) && count( $items ) < $this->opts['max']['files'] )
{
foreach( $items as $i => $item )
{
$files['data'][$i]['path'] = $item;
}
}
else
{
$files['data'] = false;
}
return $files;
}
/**
* File Excludes
*/
private function rmvFileExcludes( $files )
{
$exclude = $this->opts['file']['print'];
if( in_array( $files['names'], $exclude ) )
{
// Incomplete...
}
}
/**
* Extract Useable Data from the Files Submitted.
*
* Gets available data from the files.
*
* @param array $files
*
* @return array $files
*/
private function getFilesData( $files )
{
// Initalize counter
$files['cnt'] = count( $files['data'] );
// Put the files in a local array.
if( isset( $files['data'] ) && count( $files['data'] ) > 0 )
{
// Loop through the items.
foreach ( $files['data'] as $cnt => $item )
{
/** Check to see if the file exists... */
if ( file_exists( $item['path'] ) )
{
/** Get relevant file data. */
$item = $this->getFileData( $item );
// Add it to the array.
$files['data'][$cnt] = $item;
}
}
}
return $files;
}
/**
* Get the file name
*
* @example:
* array(5) {
* [0]=>
* string(24) "alberta-2297204_1920.jpg"
* [1]=>
* string(7) "alberta"
* [2]=>
* string(7) "2297204"
* [3]=>
* string(4) "1920"
* [4]=>
* string(3) "jpg"
* }
*
* @param array $file
*
* @return bool|array
*/
private function getFileData( $item )
{
// Initialize.
// The name as originally.
$item['name'] = null;
// The first part of the name.
$item['initials'] = null;
// Product.
$item['product'] = null;
// The UID (Universal ID) (from the image name).
$item['date'] = null;
// Count of item (within date).
$item['cnt'] = null;
// Resolution (DPI).
$item['dpi'] = null;
// The image width (from the image name).
$item['width'] = null;
// The image height (from the image name).
$item['height'] = null;
// The image extension (not filtered).
$item['ext'] = null;
if ( is_string( $item['path'] ) && strlen( $item['path'] ) > 0 )
{
$pattern = $this->getPattern( $item );
$item = $this->getPathFileName( $item );
preg_match( $pattern, $item['name'], $matches );
if( is_array( $matches ) && count( $matches) > 0 )
{
$item['name'] = isset( $matches[0] ) ? $matches[0] : '';
$item['initials'] = isset( $matches[1] ) ? $matches[1] : '';
$item['product'] = isset( $matches[2] ) ? $matches[2] : '';
$item['date'] = isset( $matches[3] ) ? $matches[3] : '';
$item['cnt'] = isset( $matches[4] ) ? $matches[4] : '';
$item['dpi'] = isset( $matches[5] ) ? $matches[5] : '';
$item['width'] = isset( $matches[6] ) ? $matches[6] : '';
$item['height'] = isset( $matches[7] ) ? $matches[7] : '';
$item['ext'] = isset( $matches[8] ) ? $matches[8] : '';
}
}
return $item;
}
/*
array(9) {
[0]=>
string(39) "brs-bowl-201909-005-180dpi-1115x612.jpg"
[1]=>
string(3) "brs"
[2]=>
string(4) "bowl"
[3]=>
string(6) "201909"
[4]=>
string(3) "005"
[5]=>
string(3) "180"
[6]=>
string(4) "1115"
[7]=>
string(3) "612"
[8]=>
string(3) "jpg"
}
*/
/**
* Get Path and File Parts
*
* @param array $item
*
* @return bool|array
*/
private function getPathFileName( $item )
{
// Initialize.
$item['name'] = null;
if( is_string( $item['path'] ) )
{
$arr = explode( '/', $item['path'] );
if( is_array( $arr ) && count( $arr ) > 1 )
{
$name = $arr[ count( $arr ) - 1 ];
if( strlen( $name ) > 0 )
{
$item['name'] = $name;
}
else
{
$item['name'] = false;
}
}
}
return $item;
}
/**
* Get the Regex Pattern
*
* @example 'mno-product-201909-001-300dpi-1200x800.jpg'
* @example /^([a-z]{1,35})-([0-9]{1,9})_([0-9]{1,5})\.([a-z]{1,4})$/"
*
* @param string $item
*
* @return string
*/
private function getPattern( $item )
{
$str = '';
// Regex Open
$str .= '/';
// Beginning Anchor
$str .= '^';
// Initials i.e. 'mno'.
$str .= '([a-z]{1,3})';
// Product name (3-24 characters) i.e. 'widget'.
$str .= '-([a-z]{3,24})';
// Date YYYYMM (6 digits).
$str .= '-([0-9]{4,6})';
// Count ### (3 digits).
$str .= '-([0-9]{3,5})';
// DPI ### (3 to 4 digits), then dpi.
$str .= '-([0-9]{2,4})dpi';
// Resolution ###x### (Optional?)
$str .= '-([0-9]{2,4})x([0-9]{2,4})';
// Extension.
$str .= '\.([a-z]{3,4})';
// End Anchor.
$str .= '$';
// Regex Close.
$str .= '/';
return $str;
}
/**
* Get the File Path and Name
*
* @param array $files
*
* @return bool|string
*/
private function getPrintFileName( $files )
{
if ( is_array( $files ) && ! empty( $files['path'] ) )
{
$file['name'] = $files['path']['output'];
$file['name'] .= $this->opts['file']['output']['csv'];
return $file['name'];
}
else
{
return false;
}
}
/**
* Get the CSV Header
*
* ID: Incremental, Integer, Primary Key
* Type: Simple (Assigned automatically, unless otherwise).
* SKU: Camera ID
* Name: File Name
*
* @param array $files
*
* @return array
*/
private function getCsvHeader( $files )
{
// Initialize
$csv = [];
/*
// The complete file name.
$item['name'] = null;
// The first part of the name.
$item['initials'] = null;
// Product.
$item['product'] = null;
// The UID (Universal ID) (from the image name).
$item['date'] = null;
// Count of item (within date).
$item['cnt'] = null;
// Resolution (DPI).
$item['dpi'] = null;
// The image width (from the image name).
$item['width'] = null;
// The image height (from the image name).
$item['height'] = null;
// The image extension (not filtered).
$item['ext'] = null;
*/
// First row equals column names (4 only initially).
$csv = [
[ 'name' => 'id', 'title' => 'ID', 'use' => 1, ],
[ 'name' => 'type', 'title' => 'Type', 'use' => 1, ],
[ 'name' => 'sku', 'title' => 'SKU', 'use' => 1, ],
[ 'name' => 'name', 'title' => 'Name', 'use' => 1, ],
[ 'name' => 'published', 'title' => 'Published', 'use' => 1, ],
[ 'name' => 'featured', 'title' => '"Is featured?"', 'use' => 1, ],
[ 'name' => 'visible', 'title' => '"Visibility in catalog"', 'use' => 1, ],
[ 'name' => 'price', 'title' => '"Regular Price"', 'use' => 1, ],
[ 'name' => 'categories', 'title' => '"Categories"', 'use' => 1, ],
[ 'name' => 'images', 'title' => 'Images', 'use' => 1, ],
];
$str = '';
foreach ( $csv as $cnt => $item )
{
if( $item['use'] )
{
// Add the Title
$str .= $item['title'];
// Add the comma.
$str .= ',';
}
}
// Remove the last comma.
$str = rtrim( $str, ',' );
// Add a line ending (required).
$str .= PHP_EOL;
return $str;
}
/**
* Generates a CSV from an array.
*
* ID: Incremental, Integer, Primary Key
* Type: Simple (Assigned automatically, unless otherwise).
* SKU: Camera ID
* Name: File Name
*
* @param array $files
*
* @return array
*/
private function getCsvData( $files )
{
// Put the files in a local array.
if( isset( $files['data'] ) && count( $files['data'] ) > 0 )
{
// Loop through the items.
foreach ( $files['data'] as $cnt => $item )
{
if ( ! isset( $item['uid'] ) )
{
continue;
}
// This should be an incremental id, primary key.
// Increment only if at least one key available.
$str .= isset( $item['uid'] ) ? $cnt . ',' : '';
// Simple Product.
$str .= isset( $item['uid'] ) ? 'simple' . ',' : '';
// Slug in WooCommerce.
$str .= isset( $item['uid'] ) ? $item['uid'] . ',' : '';
// Name in WooCommerce. Title in WordPress.
$str .= isset( $item['stub'] ) ? '"' . ucfirst( $item['stub'] ) . '",' : '';
// Published.
$str .= isset( $item['uid'] ) ? '1' . ',' : '';
// Is featured?.
$str .= isset( $item['uid'] ) ? '0' . ',' : '';
// Visibility (Hidden initially).
$str .= isset( $item['uid'] ) ? 'visible' . ',' : '';
// Regular Price.
$str .= isset( $item['uid'] ) ? '150.00' . ',' : '';
$str .= isset( $item['uid'] ) ? $this->opts['category'] . ',' : '';
$str .= isset( $item['all'] ) ? $this->getImageUrl( $item ) : '';
// Remove the trailing comma.
$str = rtrim( $str, ',' );
$str .= PHP_EOL;
}
}
return $str;
}
/**
* Get Image URL Base
*
* @return string|bool
*/
private function getImageUrl( $item )
{
// Initialize.
$url = '';
$url .= $this->opts['site']['url'];
$url .= $this->opts['media']['dir'];
$url .= $this->opts['shop']['dir'];
$url .= $this->opts['product']['dir'];
if( strlen( $url ) > 0 )
{
return sprintf('"%s/%s"', $url, $item['all'] );
}
else
{
return false;
}
}
/**
* Write Files to the Storage Medium.
*
* @param string $str
*
* @return bool
*/
private function putContents( $files )
{
if ( isset( $_GET['display'] ) )
{
pre_dump( $files['csv'] );
}
if ( isset( $_GET['print'] )
&& isset( $files['csv'] ) && strlen( $files['csv'] ) > 0 )
{
$resp = file_put_contents( $files['print'], $files['csv'] );
return $resp;
}
}
/**
* Get Message
*
* @param array $files
*
* @return string
*/
private function getMessage( $files )
{
//is_string( $str ) && strlen( $str ) > 0 && strlen( $str ) < 1000 )
if( is_array( $files ) && count( $files ) > 0 )
{
// Initialize.
$str = '';
// Count of the files.
$str .= isset( $files['cnt'] ) ?
sprintf( '<p>Files: %s</p>%s', $files['cnt'], PHP_EOL ) : '';
// Length of the files.
$str .= isset( $files['str'] ) ?
sprintf( '<p>Bytes: %s</p>%s', strlen ( $files['str'] ), PHP_EOL ) : '';
// Length of the files.
$str .= isset( $files['resp'] ) ?
sprintf( '<p>Resp: %s</p>%s', $files['resp'], PHP_EOL ) : '';
// Length of the files.
$str .= isset( $files['print'] ) ?
sprintf( '<p>File: %s</p>%s', $files['print'], PHP_EOL ) : '';
return $str;
}
else
{
return false;
}
}
/**
* File Description
*
* For use at the top of the file as needed.
*/
private function getFileDesc()
{
$str = '';
$str .= '# ' . PHP_EOL;
$str .= '# Generated by: printer.csv.php' . PHP_EOL;
$str .= '# ' . PHP_EOL;
$str .= $this->getTimeStamp();
$str .= '#' . PHP_EOL;
return $str;
}
/**
* Time Stamp (Including Created Date)
*
* @return string
*/
private function getTimeStamp()
{
$str = '';
$str .= sprintf( '# Created: %s%s',
$this->opts['date']['created'], PHP_EOL );
$str .= sprintf( '# Updated: %s%s', date( 'Y-m-d' ), PHP_EOL );
$str .= sprintf( '# Time: %s%s', date( 'H:i:s T' ), PHP_EOL );
return $str;
}
/**
* File End
*/
private function getFileEnd( $files )
{
// Initialize
$str = PHP_EOL;
$str .= '/*';
$str .= ' End of File: printer.csv.php. ';
$str .= $files['size'] . ' B. ';
$str .= '*/' . PHP_EOL;
$str .= PHP_EOL;
// Add this string to the end...
$files['str'] .= $str;
return $files;
}
/**
* Get Form
*
* @return string
*/
private function getForm()
{
if( isset( $_GET['ctrls'] ) )
{
// Initialize
$str = '';
$str .= '<form action="" method="post">' . PHP_EOL;
$str .= '<div>' . PHP_EOL;
$str .= '<input type="checkbox" name="safety" id="safety" required>' . PHP_EOL;
$str .= ' <input type="submit" class="btn" value="Run">' . PHP_EOL;
$str .= '</div>' . PHP_EOL;
$str .= '</form>' . PHP_EOL;
return $str;
}
else
{
return false;
}
}
/**
* Get the Page HTML.
*
* @param array $files
*
* @return string
*/
private function getPageHTML( $files )
{
$str = '<!DOCTYPE html>' . PHP_EOL;
$str .= '<html lang="en-CA" class="dark">' . 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 .= sprintf( '<title>%s</title>%s', $this->opts['page']['title'], PHP_EOL );
$str .= '<meta name="robots" content="noindex,nofollow" />' . PHP_EOL;
$str .= '<link rel=stylesheet href="/style.min.css">' . PHP_EOL;
$str .= '<style> main { min-height: 500px; overflow: hidden; }';
$str .= ' input { display: inline; } </style>' . PHP_EOL;
$str .= '</head>' . PHP_EOL;
$str .= '<body>' . PHP_EOL;
$str .= '<main>' . PHP_EOL;
$str .= sprintf( '<h1 style="display:block;">%s</h1>%s', $this->opts['page']['title'], PHP_EOL );
$str .= $this->getForm();
$str .= isset( $files['msg'] ) ? $files['msg'] : '';
$str .= '</main>' . PHP_EOL;
$str .= '</html>' . PHP_EOL;
return $str;
}
} // End Class
if ( ! function_exists( 'pre_dump' ) ) {
/** Dumps a formatted string or array. */
function pre_dump( $arr, $continue = 1 ) {
if ( isset( $_GET['debug'] ) ) {
if (is_string( $arr ) ) {
$arr = str_replace( ['<','>'], ['&lt','&gt'], $arr );
}
echo "<pre>" . PHP_EOL;
var_dump( $arr );
if ( isset( $_GET['exit'] ) || ! $continue ) {
exit( '<br/>' . 'Done.' );
}
echo "</pre>" . PHP_EOL;
}
}
}
/**
* CSV Printer
*/
function ec01_csv_printer()
{
$printer = new CsvPrinter();
$printer->init();
}
ec01_csv_printer();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment