Completed
Push — master ( 9b2af0...bbcc3e )
by El
03:42
created

lib/Model/Paste.php (5 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * PrivateBin
4
 *
5
 * a zero-knowledge paste bin
6
 *
7
 * @link      https://github.com/PrivateBin/PrivateBin
8
 * @copyright 2012 Sébastien SAUVAGE (sebsauvage.net)
9
 * @license   https://www.opensource.org/licenses/zlib-license.php The zlib/libpng License
10
 * @version   1.1
11
 */
12
13
namespace PrivateBin\Model;
14
15
use Exception;
16
use PrivateBin\Persistence\ServerSalt;
17
use PrivateBin\PrivateBin;
18
use PrivateBin\Sjcl;
19
20
/**
21
 * Paste
22
 *
23
 * Model of a PrivateBin paste.
24
 */
25
class Paste extends AbstractModel
26
{
27
    /**
28
     * Get paste data.
29
     *
30
     * @access public
31
     * @throws Exception
32
     * @return stdClass
33
     */
34 38
    public function get()
35
    {
36 38
        $data = $this->_store->read($this->getId());
37 38
        if ($data === false) {
38 1
            throw new Exception(PrivateBin::GENERIC_ERROR, 64);
39
        }
40
41
        // check if paste has expired and delete it if neccessary.
42 37
        if (property_exists($data->meta, 'expire_date')) {
43 5
            if ($data->meta->expire_date < time()) {
44 4
                $this->delete();
45 4
                throw new Exception(PrivateBin::GENERIC_ERROR, 63);
46
            }
47
            // We kindly provide the remaining time before expiration (in seconds)
48 1
            $data->meta->remaining_time = $data->meta->expire_date - time();
49
        }
50
51
        // set formatter for for the view.
52 33
        if (!property_exists($data->meta, 'formatter')) {
53
            // support < 0.21 syntax highlighting
54 6
            if (property_exists($data->meta, 'syntaxcoloring') && $data->meta->syntaxcoloring === true) {
55 2
                $data->meta->formatter = 'syntaxhighlighting';
56
            } else {
57 4
                $data->meta->formatter = $this->_conf->getKey('defaultformatter');
58
            }
59
        }
60
61
        // support old paste format with server wide salt
62 33
        if (!property_exists($data->meta, 'salt')) {
63 4
            $data->meta->salt = ServerSalt::get();
64
        }
65 33
        $data->comments       = array_values($this->getComments());
66 33
        $data->comment_count  = count($data->comments);
67 33
        $data->comment_offset = 0;
68 33
        $data->{'@context'}   = 'js/paste.jsonld';
69 33
        $this->_data          = $data;
70 33
        return $this->_data;
71
    }
72
73
    /**
74
     * Store the paste's data.
75
     *
76
     * @access public
77
     * @throws Exception
78
     */
79 35
    public function store()
80
    {
81
        // Check for improbable collision.
82 35
        if ($this->exists()) {
83 3
            throw new Exception('You are unlucky. Try again.', 75);
84
        }
85
86 33
        $this->_data->meta->postdate = time();
87 33
        $this->_data->meta->salt     = serversalt::generate();
88
89
        // store paste
90
        if (
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
91 33
            $this->_store->create(
92 33
                $this->getId(),
93 33
                json_decode(json_encode($this->_data), true)
94 33
            ) === false
95
        ) {
96
            throw new Exception('Error saving paste. Sorry.', 76);
97
        }
98 33
    }
99
100
    /**
101
     * Delete the paste.
102
     *
103
     * @access public
104
     * @throws Exception
105
     */
106 24
    public function delete()
107
    {
108 24
        $this->_store->delete($this->getId());
109 24
    }
110
111
    /**
112
     * Test if paste exists in store.
113
     *
114
     * @access public
115
     * @return bool
116
     */
117 82
    public function exists()
118
    {
119 82
        return $this->_store->exists($this->getId());
120
    }
121
122
    /**
123
     * Get a comment, optionally a specific instance.
124
     *
125
     * @access public
126
     * @param string $parentId
127
     * @param string $commentId
128
     * @throws Exception
129
     * @return Comment
130
     */
131 20
    public function getComment($parentId, $commentId = null)
132
    {
133 20
        if (!$this->exists()) {
134 1
            throw new Exception('Invalid data.', 62);
135
        }
136 19
        $comment = new Comment($this->_conf, $this->_store);
137 19
        $comment->setPaste($this);
138 19
        $comment->setParentId($parentId);
139 17
        if ($commentId !== null) {
140 5
            $comment->setId($commentId);
141
        }
142 17
        return $comment;
143
    }
144
145
    /**
146
     * Get all comments, if any.
147
     *
148
     * @access public
149
     * @return array
150
     */
151 33
    public function getComments()
152
    {
153 33
        return $this->_store->readComments($this->getId());
154
    }
155
156
    /**
157
     * Generate the "delete" token.
158
     *
159
     * The token is the hmac of the pastes ID signed with the server salt.
160
     * The paste can be deleted by calling:
161
     * http://example.com/privatebin/?pasteid=<pasteid>&deletetoken=<deletetoken>
162
     *
163
     * @access public
164
     * @return string
165
     */
166 32
    public function getDeleteToken()
167
    {
168 32
        if (!property_exists($this->_data->meta, 'salt')) {
169
            $this->get();
170
        }
171 32
        return hash_hmac(
172 32
            $this->_conf->getKey('zerobincompatibility') ? 'sha1' : 'sha256',
173 32
            $this->getId(),
174 32
            $this->_data->meta->salt
175
        );
176
    }
177
178
    /**
179
     * Set paste's attachment.
180
     *
181
     * @access public
182
     * @param string $attachment
183
     * @throws Exception
184
     */
185 2 View Code Duplication
    public function setAttachment($attachment)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
186
    {
187 2
        if (!$this->_conf->getKey('fileupload') || !Sjcl::isValid($attachment)) {
188
            throw new Exception('Invalid attachment.', 71);
189
        }
190 2
        $this->_data->meta->attachment = $attachment;
191 2
    }
192
193
    /**
194
     * Set paste's attachment name.
195
     *
196
     * @access public
197
     * @param string $attachmentname
198
     * @throws Exception
199
     */
200 2 View Code Duplication
    public function setAttachmentName($attachmentname)
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
201
    {
202 2
        if (!$this->_conf->getKey('fileupload') || !Sjcl::isValid($attachmentname)) {
203
            throw new Exception('Invalid attachment.', 72);
204
        }
205 2
        $this->_data->meta->attachmentname = $attachmentname;
206 2
    }
207
208
    /**
209
     * Set paste expiration.
210
     *
211
     * @access public
212
     * @param string $expiration
213
     */
214 7
    public function setExpiration($expiration)
215
    {
216 7
        $expire_options = $this->_conf->getSection('expire_options');
217 7
        if (array_key_exists($expiration, $expire_options)) {
218 5
            $expire = $expire_options[$expiration];
219
        } else {
220
            // using getKey() to ensure a default value is present
221 2
            $expire = $this->_conf->getKey($this->_conf->getKey('default', 'expire'), 'expire_options');
222
        }
223 7
        if ($expire > 0) {
224 7
            $this->_data->meta->expire_date = time() + $expire;
225
        }
226 7
    }
227
228
    /**
229
     * Set paste's burn-after-reading type.
230
     *
231
     * @access public
232
     * @param string $burnafterreading
233
     * @throws Exception
234
     */
235 3
    public function setBurnafterreading($burnafterreading = '1')
236
    {
237 3
        if ($burnafterreading === '0') {
238 1
            $this->_data->meta->burnafterreading = false;
239
        } else {
240 3
            if ($burnafterreading !== '1') {
241 2
                throw new Exception('Invalid data.', 73);
242
            }
243 1
            $this->_data->meta->burnafterreading = true;
244 1
            $this->_data->meta->opendiscussion   = false;
245
        }
246 1
    }
247
248
    /**
249
     * Set paste's discussion state.
250
     *
251
     * @access public
252
     * @param string $opendiscussion
253
     * @throws Exception
254
     */
255 11
    public function setOpendiscussion($opendiscussion = '1')
256
    {
257
        if (
258 11
            !$this->_conf->getKey('discussion') ||
259 11
            $this->isBurnafterreading() ||
260 11
            $opendiscussion === '0'
261
        ) {
262 1
            $this->_data->meta->opendiscussion = false;
263
        } else {
264 11
            if ($opendiscussion !== '1') {
265 2
                throw new Exception('Invalid data.', 74);
266
            }
267 9
            $this->_data->meta->opendiscussion = true;
268
        }
269 9
    }
270
271
    /**
272
     * Set paste's format.
273
     *
274
     * @access public
275
     * @param string $format
276
     * @throws Exception
277
     */
278 8
    public function setFormatter($format)
279
    {
280 8
        if (!array_key_exists($format, $this->_conf->getSection('formatter_options'))) {
281 2
            $format = $this->_conf->getKey('defaultformatter');
282
        }
283 8
        $this->_data->meta->formatter = $format;
284 8
    }
285
286
    /**
287
     * Check if paste is of burn-after-reading type.
288
     *
289
     * @access public
290
     * @throws Exception
291
     * @return bool
292
     */
293 25 View Code Duplication
    public function isBurnafterreading()
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
294
    {
295 25
        if (!property_exists($this->_data, 'data')) {
296 14
            $this->get();
297
        }
298 23
        return property_exists($this->_data->meta, 'burnafterreading') &&
299 23
               $this->_data->meta->burnafterreading === true;
300
    }
301
302
    /**
303
     * Check if paste has discussions enabled.
304
     *
305
     * @access public
306
     * @throws Exception
307
     * @return bool
308
     */
309 13 View Code Duplication
    public function isOpendiscussion()
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
310
    {
311 13
        if (!property_exists($this->_data, 'data')) {
312 8
            $this->get();
313
        }
314 13
        return property_exists($this->_data->meta, 'opendiscussion') &&
315 13
               $this->_data->meta->opendiscussion === true;
316
    }
317
}
318