<?php
class BrokenSignException extends \Exception {}
class ExportableData
{
protected static function getCost()
{
return 13;
}
private $data;
private $filename;
/**
* Constructor from data
* @param mixed $data Data to save
*/
public function __construct($data)
{
$this->data = $data;
}
/**
* Exports data to specified file
* @param string $filename Filename
*/
public function export($filename)
{
$this->filename = $filename;
$this->save($this->exportToString());
}
/**
* Export data to string
* @return string Exported data
*/
public function exportToString()
{
return serialize($this->sign());
}
/**
* Import signed data from string
* @param string $data Signed data
* @return ExportableData Instance of @a ExportableData
* @throws BrokenSignException If sign verification failed
*/
public static function importFromString($data)
{
$me = new static(null);
$me->verify(unserialize($data));
return $me;
}
/**
* Data getter
* @return mixed User data
*/
public function getData()
{
return $this->data;
}
/**
* Import signed data from specified file
* @param string $filename Filename
* @return ExportableData Instance of @a ExportableData with data from file
* @throws BrokenSignException If sign verification failed
*/
public static function import($filename)
{
$me = new static(null);
$me->filename = $filename;
$me->verify($me->load());
return $me;
}
protected load()
{
return unserialize(file_get_contents($this->filename));
}
protected function verify(array $rawData)
{
if (!password_verify($rawData[0], $rawData[1])) {
throw new BrokenSignException();
}
$this->data = unserialize(base64_decode($rawData[1]));
}
protected function sign()
{
$serialized = base64_encode(serialize($this->data));
$sign = password_hash($serialized, PASSWORD_BCRYPT, ['cost' => static::getCost()]);
return [$serialized, $sign];
}
protected function save($rawData)
{
file_put_contents($this->filename, $rawData);
}
}
// Example
// Saving
/** @var mixed $product */
$exportable = new ExportableData($product);
$exportable->export('somefile.sav');
// Or if you want to get file as string
$exportable->exportToString();
// Loading
$data = null;
try {
// if you got file as string
$data = ExportableData::importFromString($stringData);
// if you got file
$data = ExportableData::import($filename);
} catch (BrokenSignException $e) {
die('Data is broken!');
}
$product = $data->getData();
<?php
/**
* Validates some data against some constraints set in @a $validationMapping
* @param array $validationMapping Constraints with structure ['fieldName' => 'callback']
* @param array $data Data to validate with structure ['fieldName' => 'fieldData']
* @param bool $stopOnError Whether to stop on first occured error
* @return bool|array True if validation passed, array of fields with errors (['fieldName' => 'validationResult']) otherwise
*/
function validate(array $validationMapping, array $data, $stopOnError = false) {
$hasErrors = false;
$fieldsWithErrors = [];
foreach ($validationMapping as $fieldName => $validator) {
$validationResult = $validator(isset($data[$fieldName]) ? $data[$fieldName] : null, $fieldName);
if ($validationResult !== false) {
$hasErrors = true;
$fieldsWithErrors[$fieldName] = $validationResult;
}
if ($stopOnError && $hasErrors) {
break;
}
}
return count($fieldsWithErrors) ? $fieldsWithErrors : true;
}
// example
function notEmptyValidator($fieldData, $fieldName) {
return empty($fieldData) ? sprintf('%s is empty!', $fieldName) : false;
}
function lengthValidatorFactory($minValue = null, $maxValue = null) {
return function ($fieldData, $fieldName) use ($minValue, $maxValue) {
if (!isset($fieldData)) {
return isset($minValue) ?
($minValue > 0 ? sprinf('%s must be longer than %d', $fieldName, $minValue) : false) :
false;
}
if (isset($minValue)) {
if (mb_strlen($fieldData) < $minValue) {
return sprinf('%s must be longer than %d', $fieldName, $minValue);
}
}
if (isset($maxValue)) {
if (mb_strlen($fieldData) > $maxValue) {
return sprinf('%s must be shorter than %d', $fieldName, $maxValue);
}
}
return false;
};
}
$result = validate([
'name' => 'notEmptyValidator',
'password' => lengthValidatorFactory(4),
'email' => lengthValidatorFactory(4, 20),
], $POST['someForm']);
if ($result === false) {
echo 'Success!';
} else {
echo '<ul><li>' . implode('</li></li>', $result) . '</li></ul>';
}
<?php
/* SOME LOGIC HERE */
/* where $someData and $username is defined */
export([
'someVariableYouWantToUseInTemplate' => $someData,
'name' => $username,
]);
require 'template.php';
Hello, <b><?= $username; ?></b>!
<?php
class GeoPosition {
private $data;
public function __construct(array $data)
{
$this->data = $data;
}
public function getData()
{
return $this->data;
}
public function __toString()
{
return $data['data'];
}
}
/** @var array[] $dbResponse */
$normalizedData = array_map(function (array $geoPosition) {
return new GeoPosition($geoPosition);
}, $dbResponse);
$filteredData = array_unique($normalizedData, SORT_STRING);
$denormalized = array_map(function (GeoPosition $geoPosition) {
return $geoPosition->getData();
}, $filteredData);
<?php
function extractIntervals(array $data) {
$result = [array_shift($data)];
array_walk($data, function ($element) use (&$result) {
$i = count($result) - 1;
$j = count($result[$i]) - 1;
$diff = $element - $result[$i][$j];
if ($diff > 1) {
$result[$i][] = $element;
} else {
$result[] = [$element];
}
});
return $result;
}
function extractStringIntervals(array $data) {
return implode(', ', array_map(function (array $interval) {
$first = $interval[0];
$last = $interval[count($interval) - 1];
return $first == $last ? $first : ($first . '-' . $last);
}, extractIntervals($data)));
}