Warning: chmod(): Operation not permitted in /var/www/hopeinstoughton_www/wp-content/plugins/simple-universal-google-analytics/main.php on line 8 [0] in function chmod in /var/www/hopeinstoughton_www/wp-content/plugins/simple-universal-google-analytics/main.php on line 8 [1] in function include_once in /var/www/hopeinstoughton_www/wp-settings.php on line 560 [2] in function require_once in /var/www/hopeinstoughton_www/wp-config.php on line 85 [3] in function require_once in /var/www/hopeinstoughton_www/wp-load.php on line 50 [4] in function require_once in /var/www/hopeinstoughton_www/wp-blog-header.php on line 13 [5] in function require in /var/www/hopeinstoughton_www/index.php on line 17
| Server IP : 94.177.8.99 / Your IP : 216.73.217.165 Web Server : Apache/2.4.58 (Ubuntu) System : Linux aries 6.8.0-134-generic #134-Ubuntu SMP PREEMPT_DYNAMIC Fri Jun 26 18:43:11 UTC 2026 x86_64 User : www-data ( 33) PHP Version : 8.1.34 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/patientapps_www/modules/patientapps/model/ |
Upload File : |
<?php
/*
From the single-language json file (with images)
- update database
- using extra data from the database
- create a multi-language json file
- create a multi-language sql3 file
this is for the TEMPLATES only (parent_template = NULL) - the personalized copy is built from this.
database - images:
procedure_code, language, name(image), imagehash
image files stored on the filesystem, under the imagehash
database - text:
procedure_code, language, json_encoded(basic data)
also required: garbage collection
THE MAXIMUM SIZE of data.json is 5MB. This is a designed browser limitation
https://developer.chrome.com/docs/extensions/reference/storage/
*/
class Target_Model extends Database_Model {
private $targetDirectory;
private $language = 'en';
private $procedure_code = FALSE;
private $content = FALSE;
// private $workfolder;
private $debug = FALSE;
private $parent_template = NULL;
public function __construct() {
parent::__construct();
/* $this->workfolder = HOME . '/storage/patientapps/json-cache'; // image cache - from files included in the json
if (!file_exists($this->workfolder)) {
@mkdir($this->workfolder);
} */
}
public function TargetDirectory() {
if (func_num_args()) {
$this->targetDirectory = rtrim(func_get_arg(0), '/');
return $this;
}
return $this->targetDirectory;
}
public function Debug() {
if (func_num_args()) {
$this->debug = func_get_arg(0);
return $this;
}
return $this->debug;
}
public function Language() {
if (func_num_args()) {
$this->language = func_get_arg(0);
$this->_updateDatabase();
return $this;
}
return $this->language;
}
public function ProcedureCode() { // this is the base filename
if (func_num_args()) {
$this->procedure_code = func_get_arg(0);
$this->_updateDatabase();
return $this;
}
return $this->procedure_code;
}
public function ContentJson() { // everything in the content should be base64_encoded
if (func_num_args()) {
$this->content = func_get_arg(0);
$this->_updateDatabase();
return $this;
}
return $this->content;
}
private function _updateDatabase() {
// we have everything required - update the database entries
if ($this->language !== FALSE && $this->procedure_code !== FALSE && $this->content !== FALSE) {
// note the old data (if present)
$old_data = [];
$json = $this->Query('select content from `pai_json_head`')
->Where('procedure_code=%s', $this->ProcedureCode())
->Where('language_code=%s', $this->Language())
->Get()
->First();
if (!is_null($json)) {
$old_data['data.json'] = sha1($json->content, FALSE); // we don't need the content, only to see if it has changed
}
$images = $this->Query('select name,hash from `pai_json_tail`')
->Where('procedure_code=%s', $this->ProcedureCode())
->Where('language_code=%s', $this->Language())
->Get();
foreach($images as $image) {
$old_data[$image->name] = $image->hash;
}
// prepare the new
$new_data = [];
foreach($this->content as $name => $value) {
$iscontent = strpos($name, '.json') !== FALSE; // text is json_encoded
if (!$iscontent) $value = base64_decode($value); // images are base64 encoded
$new_data[$name] = sha1($value, FALSE);
}
foreach($new_data as $key => $new_hash) {
$old_hash = $old_data[$key] ?? '';
$iscontent = strpos($key, '.json') !== FALSE;
$value = base64_decode($this->content[$key]);
if ($old_hash == $new_hash) { // unchanged - no need to update database
unset($new_data[$key], $old_data[$key]);
} elseif ($iscontent) { // json has changed - update it
$this->TableName('pai_json_head')
->InsertOrUpdate([
'procedure_code' => $this->ProcedureCode(),
'language_code' => $this->Language(),
], [
'content' => $value,
]);
unset($new_data[$key], $old_data[$key]);
} else { // image has changed
$this->TableName('pai_json_tail')
->InsertOrUpdate([
'procedure_code' => $this->ProcedureCode(),
'language_code' => $this->Language(),
'name' => $key,
], [
'hash' => $new_hash,
]);
/* if (!file_exists( "{$this->workfolder}/$new_hash")) {
file_put_contents("{$this->workfolder}/$new_hash", $value);
} */
unset($new_data[$key], $old_data[$key]);
}
}
// delete whatever remains in old_data from the database (leave the filesytem)
foreach($old_data as $key => $value) {
$iscontent = strpos($key, '.json') !== FALSE;
if (!$iscontent) {
$this->Query('delete from `pai_json_tail`')
->Where('procedure_code=%s', $this->ProcedureCode())
->Where('language_code=%s', $this->Language())
->Where('name=%s', $key)
->Get();
}
}
}
}
// this points to the orginal template, if we are needing to create a customized one from it
// customized items are not added to the database
public function ParentTemplate() {
if (func_num_args()) {
$this->parent_template = func_get_arg(0);
return $this;
}
return $this->parent_template;
}
public function getFilename($ext = '.json') {
return $this->targetDirectory . '/' . $this->procedure_code . $ext;
}
private function _InsertBlob($db, $node) {
$stmt = $db->prepare("INSERT INTO blobs (name, wd, ht, mimetype, data) values (:name, :wd, :ht, :mime, :data)");
$stmt->bindValue(':name', $node['name'], SQLITE3_TEXT);
$stmt->bindValue(':wd', $node['wd'], SQLITE3_INTEGER);
$stmt->bindValue(':ht', $node['ht'], SQLITE3_INTEGER);
$stmt->bindValue(':mime', $node['mime'], SQLITE3_TEXT);
$stmt->bindValue(':data', $node['data'], SQLITE3_BLOB);
$stmt->execute();
$stmt->reset();
}
private function _sqlite_InsertImage($db, $name, $imagedata) {
if (empty($imagedata)) {
$img = FALSE;
} else {
$img = imagecreatefromstring($imagedata);
}
if ($img !== FALSE) {
$finfo = new finfo(FILEINFO_MIME_TYPE);
$mimetype = $finfo->buffer($imagedata);
$node = [
'name' => $name,
'wd' => imagesx($img),
'ht' => imagesy($img),
'mime' => $mimetype,
'data' => base64_encode($imagedata), // images must be base64 encoded, otherwise the `select data from blobs` function will FAIL
];
imagedestroy($img);
$this->_InsertBlob($db, $node);
}
}
private function _RebuildJSONFile($final) {
$filename = $this->getFilename('.json');
$final['data.json'] = base64_encode($final['data.json']);
file_put_contents($filename, str_replace('\\/', '/', json_encode($final)));
}
// recreate the sqlite3 file
private function _RebuildSQLiteFile($final) { // data.json & images are base64 encoded. master.json is an object
$filename = $this->getFilename('.sql3');
@unlink($filename);
$db = new SQLite3($filename);
$sql = <<<BLOCK
create table blobs (
name text[40] PRIMARY KEY,
wd integer,
ht integer,
mimetype text,
data blob
)
BLOCK;
$db->exec($sql);
foreach($final as $key => $value) {
if ($key == 'data.json') {
$node = ['name' => '.data', 'wd' => 0, 'ht' => 0, 'mime' => 'application/json', 'data' => $value]; // just json encoded
$this->_InsertBlob($db, $node);
} elseif ($key == 'master.json') {
$value = str_replace('\\/', '/', json_encode($value));
$node = ['name' => '.master', 'wd' => 0, 'ht' => 0, 'mime' => 'application/json', 'data' => $value]; // only json encoded
$this->_InsertBlob($db, $node);
} elseif (is_string($value)) { // image
$value = base64_decode($value);
$this->_sqlite_InsertImage($db, $key, $value);
}
}
$db->close();
}
// add an old json file to the database - json & images
public function Import($basename, $contents) {
if (strpos($basename, 'sma1') !== FALSE) {
$this->Language('es');
$basename = str_replace('sma1-', 'ma1-', $basename);
} else {
$this->Language('en');
}
foreach($contents as $key => $value) {
if (strpos($key, '.json') !== FALSE) {
$value = base64_decode($value); // this is json
$this->TableName('pai_json_head')
->InsertOrUpdate([
'procedure_code' => $basename,
'language_code' => $this->Language(),
], [
'content' => $value,
]);
} else { // image - save it, add to target folder
// create sha1
$hash = sha1($value, FALSE);
// update database
$this->TableName('pai_json_tail')
->InsertOrUpdate([
'procedure_code' => $basename,
'language_code' => $this->Language(),
'name' => $key,
], [
'hash' => $hash,
]);
}
}
}
private function _asLanguage($key) {
$result = [];
$key = strtolower($key);
switch($key) {
case 'de':
case 'es':
case 'en':
case 'pt':
case 'fr':
case 'fi': // finnish / suomi
default:
return [
'lang_id' => $key,
'lang_abbr' => $key,
];
case 'zh-cn': // simplified
return [
'lang_id' => $key, // zh-CN
'lang_abbr' => '中文',
];
case 'zh-tw': // traditional
return [
'lang_id' => $key, // zh-TW
'lang_abbr' => '中文',
];
case 'ar':
return [
'lang_id' => $key,
'lang_abbr' => 'اَلْعَرَبِيَّةُ',
'rtl' => 1,
];
}
}
public function _AddLanguage(&$master, $lang_id, $value) {
$header = $this->_asLanguage($lang_id);
unset($value['care_team']);
// move version/branding/theme
if (!isset($master['version'])) {
$master['version'] = $value['splash']['version'];
}
unset($value['splash']['version']);
$header['data'] = $value;
$master['lang'][] = $header;
}
private function _generateImageList_clean($hashlist) {
foreach($hashlist as $size => &$hashitems) {
if (count($hashitems) > 1) { // if the item is in the other list, remove it from this list
foreach($hashitems as $index => $md5) {
if (in_array($md5, $hashlist[1 - $size])) {
unset($hashitems[$index]);
}
}
}
}
return $hashlist;
}
private function _generateImageList() {
// then any images
$rows = $this->Query('select language_code,name,hash from `pai_json_tail`')
->Where('procedure_code=%s', $this->ProcedureCode())
->Get();
$output = [];
$result = [];
foreach($rows as $row) {
$name = $row->name;
if (substr($name, 0, 2) == 'b-') {
[$hash, $size] = explode('.', $name);
} else {
$hash = $name;
$size = 2;
}
if (!isset($output[$hash][$size])) $output[$hash][$size] = [];
if (!in_array($row->hash, $output[$hash][$size])) {
$output[$hash][$size][] = $row->hash;
}
}
foreach($output as $hash => &$hashlist) {
if (isset($hashlist[0]) && isset($hashlist[1])) {
$this->_generateImageList_clean($hashlist);
}
foreach($hashlist as $size => $md5) {
$res = new \StdClass;
$res->hash = array_pop($md5);
if ($size == 2) {
$res->name = $hash;
} else {
$res->name = $hash . '.' . $size;
}
$result[] = $res;
}
}
return $result;
}
private function _getBySHA($hash) {
$row = $this->Query('select pm_data from `pai_media`')
->Where('pm_contenthash=%s', $hash)
->Get()
->First();
$res = $row->pm_data ?? '';
// if ($res == '') error_log('missing sha: ' . $hash);
return $res;
}
public function GenerateFiles($action_theme = FALSE) {
// create the json file using data from the database
$final = [];
// Page data first
$rows = $this->Query('select language_code,content from `pai_json_head`')
->Where('procedure_code=%s', $this->ProcedureCode())
->Get();
$first = FALSE;
$master = ['lang' => [] ];
foreach($rows as $index => $row) {
$lang = $row->language_code;
if ($first === FALSE || $lang == 'en') $first = $row->content; // jsonified
$this->_AddLanguage($master, $lang, json_decode($row->content, TRUE));
}
$final['data.json'] = $first; // english, or single language, only used by <ver2.0
if ($action_theme !== FALSE) {
$master['theme'] = $action_theme;
}
// create the new structure
$final['master.json'] = $master; // used by ver2.0 +
// var_dump($master);
// die('Breakpoint');
// then any images
/* $rows = $this->Query('select language_code,name,hash from `pai_json_tail`')
->Where('procedure_code=%s', $this->ProcedureCode())
->Get(); */
$rows = $this->_generateImageList(); // if the same image is used in normal vs wide, avoid using it
foreach($rows as $row) {
$hash = $row->hash;
$name = $row->name;
if (!isset($final[$name])) {
$value = $this->_getBySHA($hash);
/* $filename = "{$this->workfolder}/$hash";
if (file_exists($filename)) {
$value = file_get_contents($filename);
} else {
$value = '';
} */
$final[$name] = base64_encode($value);
}
}
$this->_RebuildSQLiteFile($final);
$this->_RebuildJSONFile($final);
}
}