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/theyoungdesigners_com/modules/refresh/model/ |
Upload File : |
<?php
class Refresh_model extends Database_Model {
// TO DO: email, street address and phone numbers should be anonymized
public function __construct() {
parent::__construct();
}
// get a list of all tables to be refreshed
public function getTableNames() {
$result = [];
$rows = $this->Query('show tables')
->Get();
foreach($rows as $row) {
$data = $row->AsArray();
$tablename = array_pop($data);
$result[] = [
'type' => 'table',
'name' => $tablename,
];
}
// to do: execute hook to remove non-exportable tables and add media images
$result = hook_execute('global.prepare', $result); // add a callable to do custom backups - such as images
return $result;
}
// is the authorization valid?
public function checkAuth($auth, $tablename) {
$auth = base64_decode(str_pad(strtr($auth, '-_', '+/'), strlen($auth) % 4, '=', STR_PAD_RIGHT));
// load private key
$settings = $this->SettingGet('config.module_info', NULL);
$priv_key = isset($settings['key']) ? $settings['key'] : '';
$priv_key = openssl_pkey_get_private($priv_key);
// decrypt payload
$payload = $this->decryptData($priv_key, $auth);
if (strpos($payload, ':') === FALSE) {
return [
'result' => 711994,
'message' => 'Unrecognized Auth Code',
'summary' => [],
];
}
[ $table, $expire ] = explode(':', $payload);
if ($table != $tablename) {
return [
'result' => 711995,
'message' => 'Invalid Auth Code', // for wrong table
'summary' => [],
];
}
if ($expire < time() ) {
return [
'result' => 711996,
'message' => 'Expired Auth Code',
'summary' => [],
];
}
return NULL;
}
public function decryptData($privkey, $data) {
$info = openssl_pkey_get_details($privkey);
$blocksize = intval($info['bits'] / 8);
$output = '';
foreach(str_split($data, $blocksize) as $chunk) {
$decrypted_data = '';
openssl_private_decrypt($chunk, $decrypted_data, $privkey, OPENSSL_PKCS1_PADDING);
if ($decrypted_data == '') return FALSE; // corrupted
$output .= $decrypted_data;
}
return $output;
}
public function encryptData($pubkey, $data) {
$info = openssl_pkey_get_details($pubkey);
$blocksize = intval(($info['bits'] - 88) / 8);
$output = '';
if ($blocksize <= 0) {
die("Unable to encryptData - no key present [5]");
}
foreach(str_split($data, $blocksize) as $chunk) {
$encrypted = '';
$j = @openssl_public_encrypt($chunk, $encrypted, $pubkey, OPENSSL_PKCS1_PADDING );
if ($j === FALSE) return FALSE; // failed to encrypt - bad public public
$output .= $encrypted;
}
return rtrim(strtr(base64_encode($output),'+/','-_'),'=');
}
private function generateAuth($tablename) {
$settings = $GLOBALS['loader']->LoadModuleSettings(__DIR__); // master / publickey
// generate authorization
$pubkey = openssl_get_publickey($settings['publickey']);
$expire = time() + 1800;
return [
$settings['master'],
$this->encryptData($pubkey, "$tablename:$expire"),
];
}
public function processTable($tablename) {
$choices = $this->getTableNames();
$found = NULL;
foreach($choices as $index => $choice) {
if ($choice['name'] == $tablename) {
$found = $choice;
break;
}
}
// if table is exportable
if (is_null($found)) {
return [
'result' => 77101,
'message' => "Unable to export '{$tablename}'",
];
}
$res = [];
$n = new \CurlObject();
$start = 0;
do {
$rows = [];
[$master, $auth] = $this->generateAuth($tablename); // generate authorization
$n ->URL($master . '/~/refresh/table-summary/' . $tablename . '/' . $start)
->RequestHeader('x-auth', $auth)
->RequestHeader('Content-type', 'application/json')
->Method('GET')
->Execute();
$body = json_decode($n->Body(), TRUE);
$rows = $body['summary'] ?? [];
if (count($rows)) {
$this->_processTable_getChangedFiles($tablename, $body);
}
$start += count($rows);
} while (count($rows) > 0);
// download everything in table, in pages of 2048 entries: primarykey, contenthash
// update changed records
// remove deleted items
return $res;
}
private function _processTable_UpdateRow($row, $primaries) {
// update the record in the database
$primary = [];
foreach($primaries as $field) {
$primary[$field] = $row[$field];
unset($row[$field]);
}
$this->InsertOrUpdate($primary, $row);
$this->DbErr();
}
// download the changed items - this is a POST
private function _processTable_downloadChangedFiles($tablename, $body) {
$n = new \CurlObject();
[$master, $auth] = $this->generateAuth($tablename); // generate authorization
$keys = array_column($body['summary'], 'key');
$n ->URL($master . '/~/refresh/table-summary/' . $tablename)
->RequestHeader('x-auth', $auth)
->RequestHeader('Content-type', 'application/json')
->postdataJson(['key' => $keys])
->Method('POST')
->Execute();
$data = json_decode($n->Body(), TRUE);
if (isset($data['data'])) {
$this->TableName($tablename);
foreach($data['data'] as $row) {
$this->_processTable_UpdateRow($row, $body['primary']);
}
}
}
private function _processTable_getChangedFiles($tablename, $body) {
$local_records = $this->generateTableSummary($tablename, $body); // fetch all records for the given primary keys
$local_index = [];
foreach($local_records['summary'] as $entry) {
$local_index[$entry['key']] = $entry['hash'];
}
// remove everything unchanged
foreach($body['summary'] as $index => $entry) {
if (($local_index[$entry['key']] ?? '') == $entry['hash']) { // unchanged - no need to download
unset($body['summary'][$index]);
}
}
if (count($body['summary'])) {
$body['summary'] = array_values($body['summary']);
// request download of changed items
$this->_processTable_downloadChangedFiles($tablename, $body);
}
}
private function _asRowHash($row, $PRIMARY, $fields) {
$keydata = [];
foreach($PRIMARY as $fieldname) {
$keydata[] = $row->{$fieldname};
}
$payload = '';
foreach($fields as $fieldname) {
$payload .= $row->{$fieldname} . '|';
}
$output = [
'key' => join(';', $keydata),
'hash' => md5($payload),
];
return $output;
}
private function _generateWhereClause($primary, $keys) {
$engine = $this->DatabaseEngine();
$c = count($primary) == 1;
$output = '';
if ($c) {
$primary = array_pop($primary);
foreach($keys as $key) {
if ($output != '') $output .= ',';
$output .= $engine->formatString($key);
}
$output = "`$primary` in ($output)";
} else {
foreach($keys as $keylist) {
$keys = explode(';', $keylist);
$entry = '';
foreach($keys as $key) {
if ($entry != '') $entry .= ',';
$entry .= $engine->formatString($key);
}
if ($output != '') $output .= ',';
$output .= "($entry)";
}
$key = '';
foreach($primary as $field) {
if ($key != '') $key .= ',';
$key .= "`$field`";
}
$output = "($key) in ($output)";
}
return $output;
}
public function generateTableSummary($tablename, $start) {
$PRIMARY = [];
$output = [
'table' => $tablename,
];
// determine primary fields - this is specific to mysql
$this->Query('select 1'); // this will initialize the database. we don't do anything with this query
$engine = $this->DatabaseEngine();
$definition = $engine->GetTableDefinition($tablename);
$PRIMARY = array_values($definition['index']['PRIMARY']['fields']);
$output['primary'] = $PRIMARY;
// prepare field mapping: remove primary, alpha sort
$fields = array_keys($definition['fields']);
foreach($PRIMARY as $fieldname) {
$p = array_search($fieldname, $fields);
if ($p !== FALSE) unset($fields[$p]);
}
sort($fields);
if (is_array($start)) { // this will be a comparison
$fields = $start['fields']; // get fields from $start structure
$keys = array_column($start['summary'], 'key');
$where = $this->_generateWhereClause($start['primary'], $keys);
$rows = $this->Query("select * from `$tablename`")
->Where($where)
->Get();
// generate whereIn clause -> add that to the $output structure
// run query
} else {
$order = join(',', $PRIMARY);
// run query
$rows = $this->Query("select * from `$tablename` order by $order limit %d,2048", $start)
->Get();
}
$this->DbErr();
$output['fields'] = $fields;
$payload = [];
foreach($rows as $row) {
$payload[] = $this->_asRowHash($row, $PRIMARY, $fields);
}
$output['summary'] = $payload;
return $output;
}
public function returnChangedRows($tablename, $primaries) {
$this->Query('select 1'); // this will initialize the database. we don't do anything with this query
$engine = $this->DatabaseEngine();
$definition = $engine->GetTableDefinition($tablename);
$PRIMARY = array_values($definition['index']['PRIMARY']['fields']);
$where = $this->_generateWhereClause($PRIMARY, $primaries);
$rows = $this->Query("select * from `$tablename`")
->Where($where)
->Get();
$output = [];
foreach($rows as $row) {
$output[] = $row->AsArray();
}
return ['data' => $output];
}
}