login/pass: error messages below page title
[minimedit.git] / upload.inc.php
1 <?php
2 global $journalcol;
3 $journalcol = [
4         'assign' => 'Toegewezen aan',
5         'subject' => 'Onderwerp',
6 ];
7
8 function userupload($input, $target = NULL, $filename = NULL)
9 {
10         switch ($input['error']) {
11         case UPLOAD_ERR_OK:
12                 break;
13         case UPLOAD_ERR_INI_SIZE:
14         case UPLOAD_ERR_FORM_SIZE:
15                 throw new Exception('bestand te groot');
16                 break;
17         case UPLOAD_ERR_NO_FILE:
18                 return; # current
19         default:
20                 throw new Exception('bestand niet goed ontvangen: '.$input['error']);
21         }
22
23         if (isset($target)) {
24                 if (!file_exists($target) and !@mkdir($target, 0777, TRUE)) {
25                         throw new Exception("bestand kon niet geplaatst worden in $target");
26                 }
27                 $target .= '/';
28         }
29         if (isset($filename)) {
30                 $target .= $filename;
31         }
32         else {
33                 $target .= $input['name'];
34         }
35
36         if (file_exists($target)) {
37                 throw new Exception("bestandsnaam al aanwezig op $target");
38         }
39         if (!@move_uploaded_file($input['tmp_name'], $target)) {
40                 throw new Exception("bestand kon niet worden opgeslagen in $target");
41         }
42
43         foreach (@glob('thumb/*/') as $thumbres) {
44                 # attempt to remove old derivations
45                 @unlink($thumbres . '/' . $target);
46         }
47         return $target;
48 }
49
50 function messagehtml($input)
51 {
52         # convert user textarea post to formatted html
53         global $User;
54         if (empty($input)) {
55                 return;
56         }
57         if ($User and $User->admin and preg_match('/\A<[a-z][^>]*>/', $input)) {
58                 return $input;  # allow html input as is if privileged
59         }
60         $markup = [
61                 '{&lt;((?:\w+:|/).+?)&gt;}'    => '<$1>',                # unescape link entities
62                 '{<(?:https?://)?([^>\s|]+)>}' => '<$1 $1>',             # unnamed link
63                 '{<([^>\s|]+)[\s|]([^>]+)>}'   => '<a href="$1">$2</a>', # hyperlink
64                 "/\r\n?/" => "\n",        # unix newlines
65                 "/  +\n/" => "<br />",    # trailing spaces for hard line break
66                 '{^(/data/.*\.jpe?g)\z}m'      => '<img src="/thumb/640x/\1" />', # image reference
67                 "/^[-*] (.*)$\n?/m"            => '<li>$1</li>',         # list item
68                 "/^(.+)$\n?/m"                 => "<p>$1</p>\n",         # paragraph
69                 "{^<p>(<li>.*</li>)(?:</p>\n)?}m" => "<ul>$1</ul>\n",    # list container
70                 '/_(?<!\w_)(.+?)_(?!\w)/'      => '<em>$1</em>',         # italic
71                 '/\*(?<!\w\*)(.+?)\*(?!\w)/'   => '<strong>$1</strong>', # bold
72                 '/~(?<!\w~)(.+?)~(?!\w)/'      => '<s>$1</s>',           # stricken
73                 '/`(?<!\w`)(.+?)`(?!\w)/'      => '<code>$1</code>',     # monospace
74         ];
75         return preg_replace(array_keys($markup), array_values($markup), htmlspecialchars($input));
76 }
77
78 function createcomment($input, &$Issue = NULL)
79 {
80         # insert user message as database issue/reply
81         global $User, $Db, $Page, $journalcol;
82
83         $reply = [];
84         if (isset($input['reply']) and $body = $input['reply']) {
85                 $reply['raw'] = $body;
86                 $reply['message'] = messagehtml($body);
87         }
88         if ($_FILES and !empty($_FILES['image'])) {
89                 $target = 'data/upload';
90                 if (!file_exists($target)) {
91                         throw new Exception("er is geen uploadmap aanwezig op $target");
92                 }
93                 $target .= '/' . $User->login;
94                 if ($result = userupload($_FILES['image'], $target)) {
95                         $reply['raw'] = $reply['raw'] ?? '';
96                         $reply['raw'] .= "/$result";
97                         $reply['message'] = $reply['message'] ?? '';
98                         if (preg_match('(^image/)', $_FILES['image']['type'])) {
99                                 $reply['message'] .= sprintf('<p><img src="/thumb/640x/%s" /></p>', $result);
100                         }
101                         else {
102                                 $reply['message'] .= sprintf('<p>Bijgevoegd bestand: <a href="/%s" />%s</a></p>',
103                                         $result, basename($result)
104                                 );
105                         }
106                 }
107         }
108         if (!$reply) {
109                 throw new Exception("lege inhoud");
110         }
111         if (isset($input['announce'])) {
112                 $reply['announced'] = !!$input['announce'];
113         }
114         if (isset($input['page'])) {
115                 $reply['page'] = $input['page'];
116         }
117
118         if (isset($input['id'])) {
119                 $newcomment = $input['id'];
120                 $filter = ['id = ?', $newcomment];
121                 $oldcomment = $Db->query("SELECT * FROM comments WHERE $filter[0]", [$filter[1]])->fetch();
122                 if (empty($oldcomment)) {
123                         throw new Exception('Antwoord niet gevonden');
124                 }
125
126                 $reply += [
127                         'updated' => ['now()'],
128                 ];
129                 $query = $Db->set('comments', $reply, $filter);
130                 if (!$query->rowCount()) {
131                         throw new Exception('Fout bij aanpassen');
132                 }
133
134                 if ($updated = $query->fetch()) {
135                         foreach (array_keys(get_object_vars($updated)) as $col) {
136                                 if ($updated->$col === $oldcomment->$col) {
137                                         continue; # unaltered
138                                 }
139                                 $Db->set('journal', [
140                                         'comment_id' => $newcomment,
141                                         'property'   => 'col',
142                                         'col'        => $col,
143                                         'old_value'  => $oldcomment->$col,
144                                         'value'      => $updated->$col,
145                                 ]);
146                         }
147                 }
148         }
149         else {
150                 $reply += [
151                         'page'    => "{$Page->handler}/{$Issue->id}",
152                         'author'  => $User->login,
153                 ];
154                 $query = $Db->set('comments', $reply);
155                 if (!$query->rowCount()) {
156                         throw new Exception('Fout bij opslaan');
157                 }
158                 $newcomment = $Db->dbh->lastInsertId('comments_id_seq');
159         }
160
161         if (isset($Issue)) {
162                 $row = [];
163                 foreach (array_keys($journalcol) as $col) {
164                         if (!isset($input[$col])) continue;
165                         $row[$col] = $input[$col] ?: NULL;
166                 }
167                 if (isset($input['status'])) {
168                         $reset = !empty($input['status']);
169                         if (isset($Issue->closed) !== $reset) {
170                                 $row['closed'] = $reset ? ['now()'] : NULL;
171                         }
172                 }
173                 $derived = ['updated' => ['now()']];
174                 $filter = ['id = ?', $Issue->id];
175                 $subquery = $Db->set('issues', $row + $derived, $filter);
176
177                 if ($updated = $subquery->fetch()) {
178                         foreach (array_keys($row) as $col) {
179                                 if ($updated->$col === $Issue->$col) {
180                                         continue; # unaltered
181                                 }
182                                 $Db->set('journal', [
183                                         'comment_id' => $newcomment,
184                                         'property'   => 'attr',
185                                         'col'        => $col,
186                                         'old_value'  => $Issue->$col,
187                                         'value'      => $updated->$col,
188                                 ]);
189                         }
190                         $Issue = $updated;
191                 }
192         }
193
194         return $newcomment;
195 }