added suggestions
[friendica.git/.git] / mod / uexport.php
1 <?php
2 /**
3  * @file mod/uexport.php
4  */
5
6 use Friendica\App;
7 use Friendica\Core\Hook;
8 use Friendica\Core\L10n;
9 use Friendica\Core\Renderer;
10 use Friendica\Core\System;
11 use Friendica\Database\DBA;
12 use Friendica\Database\DBStructure;
13
14 function uexport_init(App $a) {
15         /// @todo Don't forget to move this global field as static field in src/Modules
16         global $dbStructure;
17
18         if (!local_user()) {
19                 exit();
20         }
21
22         require_once("mod/settings.php");
23         settings_init($a);
24
25         $dbStructure = DBStructure::definition($a->getBasePath());
26 }
27
28 function uexport_content(App $a) {
29
30         if ($a->argc > 1) {
31                 header("Content-type: application/json");
32                 header('Content-Disposition: attachment; filename="' . $a->user['nickname'] . '.' . $a->argv[1] . '"');
33                 switch ($a->argv[1]) {
34                         case "backup":
35                                 uexport_all($a);
36                                 exit();
37                                 break;
38                         case "account":
39                                 uexport_account($a);
40                                 exit();
41                                 break;
42                         default:
43                                 exit();
44                 }
45         }
46
47         /**
48          * options shown on "Export personal data" page
49          * list of array( 'link url', 'link text', 'help text' )
50          */
51         $options = [
52                 ['uexport/account', L10n::t('Export account'), 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.')],
53                 ['uexport/backup', L10n::t('Export all'), L10n::t("Export your accout 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")],
54         ];
55         Hook::callAll('uexport_options', $options);
56
57         $tpl = Renderer::getMarkupTemplate("uexport.tpl");
58         return Renderer::replaceMacros($tpl, [
59                 '$title' => L10n::t('Export personal data'),
60                 '$options' => $options
61         ]);
62 }
63
64 function _uexport_multirow($query) {
65         global $dbStructure;
66
67         preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match);
68         $table = $match[1];
69
70         $result = [];
71         $r = q($query);
72         if (DBA::isResult($r)) {
73                 foreach ($r as $rr) {
74                         $p = [];
75                         foreach ($rr as $k => $v) {
76                                 switch ($dbStructure[$table]['fields'][$k]['type']) {
77                                         case 'datetime':
78                                                 $p[$k] = $v ?? DBA::NULL_DATETIME;
79                                                 break;
80                                         default:
81                                                 $p[$k] = $v;
82                                                 break;
83                                 }
84                         }
85                         $result[] = $p;
86                 }
87         }
88         return $result;
89 }
90
91 function _uexport_row($query) {
92         global $dbStructure;
93
94         preg_match("/\s+from\s+`?([a-z\d_]+)`?/i", $query, $match);
95         $table = $match[1];
96
97         $result = [];
98         $r = q($query);
99         if (DBA::isResult($r)) {
100
101                 foreach ($r as $rr) {
102                         foreach ($rr as $k => $v) {
103                                 switch ($dbStructure[$table]['fields'][$k]['type']) {
104                                         case 'datetime':
105                                                 $result[$k] = $v ?? DBA::NULL_DATETIME;
106                                                 break;
107                                         default:
108                                                 $result[$k] = $v;
109                                                 break;
110                                 }
111                         }
112                 }
113         }
114         return $result;
115 }
116
117 function uexport_account($a) {
118
119         $user = _uexport_row(
120                 sprintf("SELECT * FROM `user` WHERE `uid` = %d LIMIT 1", intval(local_user()))
121         );
122
123         $contact = _uexport_multirow(
124                 sprintf("SELECT * FROM `contact` WHERE `uid` = %d ", intval(local_user()))
125         );
126
127
128         $profile = _uexport_multirow(
129                 sprintf("SELECT * FROM `profile` WHERE `uid` = %d ", intval(local_user()))
130         );
131
132         $photo = _uexport_multirow(
133                 sprintf("SELECT * FROM `photo` WHERE uid = %d AND profile = 1", intval(local_user()))
134         );
135         foreach ($photo as &$p) {
136                 $p['data'] = bin2hex($p['data']);
137         }
138
139         $pconfig = _uexport_multirow(
140                 sprintf("SELECT * FROM `pconfig` WHERE uid = %d", intval(local_user()))
141         );
142
143         $group = _uexport_multirow(
144                 sprintf("SELECT * FROM `group` WHERE uid = %d", intval(local_user()))
145         );
146
147         $group_member = _uexport_multirow(
148                 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()))
149         );
150
151         $output = [
152                 'version' => FRIENDICA_VERSION,
153                 'schema' => DB_UPDATE_VERSION,
154                 'baseurl' => System::baseUrl(),
155                 'user' => $user,
156                 'contact' => $contact,
157                 'profile' => $profile,
158                 'photo' => $photo,
159                 'pconfig' => $pconfig,
160                 'group' => $group,
161                 'group_member' => $group_member,
162         ];
163
164         echo json_encode($output, JSON_PARTIAL_OUTPUT_ON_ERROR);
165 }
166
167 /**
168  * echoes account data and items as separated json, one per line
169  *
170  * @param App $a
171  * @throws Exception
172  */
173 function uexport_all(App $a) {
174
175         uexport_account($a);
176         echo "\n";
177
178         $total = 0;
179         $r = q("SELECT count(*) as `total` FROM `item` WHERE `uid` = %d ",
180                 intval(local_user())
181         );
182         if (DBA::isResult($r)) {
183                 $total = $r[0]['total'];
184         }
185         // chunk the output to avoid exhausting memory
186
187         for ($x = 0; $x < $total; $x += 500) {
188                 $r = q("SELECT * FROM `item` WHERE `uid` = %d LIMIT %d, %d",
189                         intval(local_user()),
190                         intval($x),
191                         intval(500)
192                 );
193
194                 $output = ['item' => $r];
195                 echo json_encode($output, JSON_PARTIAL_OUTPUT_ON_ERROR). "\n";
196         }
197 }