X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModule%2FSettings%2FUserExport.php;h=74bb517c39637509b5b0b70bf358d59ac42f3554;hb=142b399c848a3ff5f3e0f452361d284a1b5dc135;hp=0eaa72ffe6a518270e49f39c8b63639e87e66e55;hpb=8293d5ed0af78ae6cc5629bb1f982a7b29794d32;p=friendica.git diff --git a/src/Module/Settings/UserExport.php b/src/Module/Settings/UserExport.php index 0eaa72ffe6..74bb517c39 100644 --- a/src/Module/Settings/UserExport.php +++ b/src/Module/Settings/UserExport.php @@ -1,6 +1,6 @@ session = $session; + $this->dbaDefinition = $dbaDefinition; + } + /** * Handle the request to export data. * At the moment one can export three different data set @@ -44,84 +71,99 @@ class UserExport extends BaseSettings * * If there is an action required through the URL / path, react * accordingly and export the requested data. - **/ - public static function content(array $parameters = []) + * + * @param array $request + * @return string + * @throws ForbiddenException + * @throws InternalServerErrorException + * @throws ServiceUnavailableException + */ + protected function content(array $request = []): string { - parent::content($parameters); + if (!$this->session->getLocalUserId()) { + throw new HTTPException\ForbiddenException($this->l10n->t('Permission denied.')); + } + + parent::content(); /** * options shown on "Export personal data" page * list of array( 'link url', 'link text', 'help text' ) */ $options = [ - ['settings/userexport/account', DI::l10n()->t('Export account'), DI::l10n()->t('Export your account info and contacts. Use this to make a backup of your account and/or to move it to another server.')], - ['settings/userexport/backup', DI::l10n()->t('Export all'), DI::l10n()->t("Export your account info, contacts and all your items as json. Could be a very big file, and could take a lot of time. Use this to make a full backup of your account \x28photos are not exported\x29")], - ['settings/userexport/contact', DI::l10n()->t('Export Contacts to CSV'), DI::l10n()->t("Export the list of the accounts you are following as CSV file. Compatible to e.g. Mastodon.")], + ['settings/userexport/account', $this->l10n->t('Export account'), $this->l10n->t('Export your account info and contacts. Use this to make a backup of your account and/or to move it to another server.')], + ['settings/userexport/backup', $this->l10n->t('Export all'), $this->l10n->t('Export your account info, contacts and all your items as json. Could be a very big file, and could take a lot of time. Use this to make a full backup of your account (photos are not exported)')], + ['settings/userexport/contact', $this->l10n->t('Export Contacts to CSV'), $this->l10n->t('Export the list of the accounts you are following as CSV file. Compatible to e.g. Mastodon.')], ]; Hook::callAll('uexport_options', $options); - $tpl = Renderer::getMarkupTemplate("settings/userexport.tpl"); + $tpl = Renderer::getMarkupTemplate('settings/userexport.tpl'); return Renderer::replaceMacros($tpl, [ - '$title' => DI::l10n()->t('Export personal data'), + '$title' => $this->l10n->t('Export personal data'), '$options' => $options ]); } + /** * raw content generated for the different choices made * by the user. At the moment this returns a JSON file * to the browser which then offers a save / open dialog * to the user. - **/ - public static function rawContent(array $parameters = []) + * + * @throws HTTPException\ForbiddenException + */ + protected function rawContent(array $request = []) { - $args = DI::args(); - if ($args->getArgc() == 3) { - // @TODO Replace with router-provided arguments - $action = $args->get(2); - $user = DI::app()->user; - switch ($action) { - case "backup": - header("Content-type: application/json"); - header('Content-Disposition: attachment; filename="' . $user['nickname'] . '.' . $action . '"'); - self::exportAll(DI::app()); - exit(); + if (!$this->session->getLocalUserId()) { + throw new HTTPException\ForbiddenException($this->l10n->t('Permission denied.')); + } + + if (isset($this->parameters['action'])) { + switch ($this->parameters['action']) { + case 'backup': + header('Content-type: application/json'); + header('Content-Disposition: attachment; filename="' . DI::app()->getLoggedInUserNickname() . '.' . $this->parameters['action'] . '"'); + $this->echoAll($this->session->getLocalUserId()); break; - case "account": - header("Content-type: application/json"); - header('Content-Disposition: attachment; filename="' . $user['nickname'] . '.' . $action . '"'); - self::exportAccount(DI::app()); - exit(); + case 'account': + header('Content-type: application/json'); + header('Content-Disposition: attachment; filename="' . DI::app()->getLoggedInUserNickname() . '.' . $this->parameters['action'] . '"'); + $this->echoAccount($this->session->getLocalUserId()); break; - case "contact": - header("Content-type: application/csv"); - header('Content-Disposition: attachment; filename="' . $user['nickname'] . '-contacts.csv'. '"'); - self::exportContactsAsCSV(); - exit(); + case 'contact': + header('Content-type: application/csv'); + header('Content-Disposition: attachment; filename="' . DI::app()->getLoggedInUserNickname() . '-contacts.csv' . '"'); + $this->echoContactsAsCSV($this->session->getLocalUserId()); break; - default: - exit(); } + System::exit(); } } - private static function exportMultiRow(string $query) + + /** + * @param string $query + * @return array + * @throws \Exception + */ + private function exportMultiRow(string $query): array { - $dbStructure = DBStructure::definition(DI::app()->getBasePath(), false); + $dbStructure = $this->dbaDefinition->getAll(); - preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match); + preg_match('/\s+from\s+`?([a-z\d_]+)`?/i', $query, $match); $table = $match[1]; $result = []; $rows = DBA::p($query); while ($row = DBA::fetch($rows)) { $p = []; - foreach ($row as $k => $v) { - switch ($dbStructure[$table]['fields'][$k]['type']) { - case 'datetime': - $p[$k] = $v ?? DBA::NULL_DATETIME; - break; - default: - $p[$k] = $v; - break; + foreach ($dbStructure[$table]['fields'] as $column => $field) { + if (!isset($row[$column])) { + continue; + } + if ($field['type'] == 'datetime') { + $p[$column] = $row[$column] ?? DBA::NULL_DATETIME; + } else { + $p[$column] = $row[$column]; } } $result[] = $p; @@ -130,89 +172,113 @@ class UserExport extends BaseSettings return $result; } - private static function exportRow(string $query) + /** + * @param string $query + * @return array + * @throws \Exception + */ + private function exportRow(string $query): array { - $dbStructure = DBStructure::definition(DI::app()->getBasePath(), false); + $dbStructure = $this->dbaDefinition->getAll(); - preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match); + preg_match('/\s+from\s+`?([a-z\d_]+)`?/i', $query, $match); $table = $match[1]; $result = []; - $r = q($query); - if (DBA::isResult($r)) { - - foreach ($r as $rr) { - foreach ($rr as $k => $v) { - switch ($dbStructure[$table]['fields'][$k]['type']) { - case 'datetime': - $result[$k] = $v ?? DBA::NULL_DATETIME; - break; - default: - $result[$k] = $v; - break; - } + $rows = DBA::p($query); + while ($row = DBA::fetch($rows)) { + foreach ($row as $k => $v) { + if (empty($dbStructure[$table]['fields'][$k])) { + continue; + } + + switch ($dbStructure[$table]['fields'][$k]['type']) { + case 'datetime': + $result[$k] = $v ?? DBA::NULL_DATETIME; + break; + default: + $result[$k] = $v; + break; } } } + DBA::close($rows); + return $result; } /** * Export a list of the contacts as CSV file as e.g. Mastodon and Pleroma are doing. - **/ - private static function exportContactsAsCSV() + * + * @param int $user_id + * @throws \Exception + */ + private function echoContactsAsCSV(int $user_id) { + if (!$user_id) { + throw new \RuntimeException($this->l10n->t('Permission denied.')); + } + // write the table header (like Mastodon) echo "Account address, Show boosts\n"; // get all the contacts - $contacts = DBA::select('contact', ['addr'], ['uid' => $_SESSION['uid'], 'self' => false, 'rel' => [1,3], 'deleted' => false]); + $contacts = DBA::select('contact', ['addr', 'url'], ['uid' => $user_id, 'self' => false, 'rel' => [1, 3], 'deleted' => false]); while ($contact = DBA::fetch($contacts)) { - echo $contact['addr'] . ", true\n"; + echo ($contact['addr'] ?: $contact['url']) . ", true\n"; } DBA::close($contacts); } - private static function exportAccount(App $a) + + /** + * @param int $user_id + * @throws \Exception + */ + private function echoAccount(int $user_id) { - $user = self::exportRow( - sprintf("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval(local_user())) + if (!$user_id) { + throw new \RuntimeException($this->l10n->t('Permission denied.')); + } + + $user = $this->exportRow( + sprintf("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", $user_id) ); - $contact = self::exportMultiRow( - sprintf("SELECT * FROM `contact` WHERE `uid` = %d ", intval(local_user())) + $contact = $this->exportMultiRow( + sprintf("SELECT * FROM `contact` WHERE `uid` = %d ", $user_id) ); - $profile = self::exportMultiRow( - sprintf("SELECT *, 'default' AS `profile_name`, 1 AS `is-default` FROM `profile` WHERE `uid` = %d ", intval(local_user())) + $profile = $this->exportMultiRow( + sprintf("SELECT *, 'default' AS `profile_name`, 1 AS `is-default` FROM `profile` WHERE `uid` = %d ", $user_id) ); - $profile_fields = self::exportMultiRow( - sprintf("SELECT * FROM `profile_field` WHERE `uid` = %d ", intval(local_user())) + $profile_fields = $this->exportMultiRow( + sprintf("SELECT * FROM `profile_field` WHERE `uid` = %d ", $user_id) ); - $photo = self::exportMultiRow( - sprintf("SELECT * FROM `photo` WHERE uid = %d AND profile = 1", intval(local_user())) + $photo = $this->exportMultiRow( + sprintf("SELECT * FROM `photo` WHERE uid = %d AND profile = 1", $user_id) ); foreach ($photo as &$p) { $p['data'] = bin2hex($p['data']); } - $pconfig = self::exportMultiRow( - sprintf("SELECT * FROM `pconfig` WHERE uid = %d", intval(local_user())) + $pconfig = $this->exportMultiRow( + sprintf("SELECT * FROM `pconfig` WHERE uid = %d", $user_id) ); - $group = self::exportMultiRow( - sprintf("SELECT * FROM `group` WHERE uid = %d", intval(local_user())) + $group = $this->exportMultiRow( + sprintf("SELECT * FROM `group` WHERE uid = %d", $user_id) ); - $group_member = self::exportMultiRow( - sprintf("SELECT `group_member`.`gid`, `group_member`.`contact-id` FROM `group_member` INNER JOIN `group` ON `group`.`id` = `group_member`.`gid` WHERE `group`.`uid` = %d", intval(local_user())) + $group_member = $this->exportMultiRow( + sprintf("SELECT `group_member`.`gid`, `group_member`.`contact-id` FROM `group_member` INNER JOIN `group` ON `group`.`id` = `group_member`.`gid` WHERE `group`.`uid` = %d", $user_id) ); $output = [ - 'version' => FRIENDICA_VERSION, + 'version' => App::VERSION, 'schema' => DB_UPDATE_VERSION, - 'baseurl' => DI::baseUrl(), + 'baseurl' => $this->baseUrl, 'user' => $user, 'contact' => $contact, 'profile' => $profile, @@ -229,26 +295,25 @@ class UserExport extends BaseSettings /** * echoes account data and items as separated json, one per line * - * @param App $a + * @param int $user_id * @throws \Exception */ - private static function exportAll(App $a) + private function echoAll(int $user_id) { - self::exportAccount($a); + if (!$user_id) { + throw new \RuntimeException($this->l10n->t('Permission denied.')); + } + + $this->echoAccount($user_id); echo "\n"; - $total = DBA::count('item', ['uid' => local_user()]); + $total = Post::count(['uid' => $user_id]); // chunk the output to avoid exhausting memory for ($x = 0; $x < $total; $x += 500) { - $r = q("SELECT * FROM `item` WHERE `uid` = %d LIMIT %d, %d", - intval(local_user()), - intval($x), - intval(500) - ); - - $output = ['item' => $r]; - echo json_encode($output, JSON_PARTIAL_OUTPUT_ON_ERROR). "\n"; + $items = Post::selectToArray(Item::ITEM_FIELDLIST, ['uid' => $user_id], ['limit' => [$x, 500]]); + $output = ['item' => $items]; + echo json_encode($output, JSON_PARTIAL_OUTPUT_ON_ERROR) . "\n"; } } }