Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
100.00% covered (success)
100.00%
51 / 51
100.00% covered (success)
100.00%
19 / 19
CRAP
100.00% covered (success)
100.00%
1 / 1
Data
100.00% covered (success)
100.00%
51 / 51
100.00% covered (success)
100.00%
19 / 19
41
100.00% covered (success)
100.00%
1 / 1
 __construct
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
3
 setData
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
5
 addData
100.00% covered (success)
100.00%
6 / 6
100.00% covered (success)
100.00%
1 / 1
4
 getData
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 hasData
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
2
 removeData
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
2
 removeAllData
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 prepareQueryString
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
6
 hasQueryString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getQueryString
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getQueryStringLength
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getRawData
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasRawData
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getRawDataLength
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
2
 getMimeTypes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 hasMimeType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMimeType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getMimeTypeFromFilename
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
3
 getDefaultMimeType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2/**
3 * Pop PHP Framework (http://www.popphp.org/)
4 *
5 * @link       https://github.com/popphp/popphp-framework
6 * @author     Nick Sagona, III <dev@nolainteractive.com>
7 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
8 * @license    http://www.popphp.org/license     New BSD License
9 */
10
11/**
12 * @namespace
13 */
14namespace Pop\Http\Client;
15
16use Pop\Http\HttpFilterableTrait;
17
18/**
19 * Client request data class
20 *
21 * @category   Pop
22 * @package    Pop\Http
23 * @author     Nick Sagona, III <dev@nolainteractive.com>
24 * @copyright  Copyright (c) 2009-2024 NOLA Interactive, LLC. (http://www.nolainteractive.com)
25 * @license    http://www.popphp.org/license     New BSD License
26 * @version    5.0.0
27 */
28class Data
29{
30
31    use HttpFilterableTrait;
32
33    /**
34     * Raw data constant
35     */
36    const POP_CLIENT_REQUEST_RAW_DATA = 'POP_CLIENT_REQUEST_RAW_DATA';
37
38    /**
39     * Data fields (form fields and files)
40     *    $data = [
41     *      'username' => 'admin'
42     *      'file1'     => [
43     *          'filename'    => __DIR__ . '/path/to/file.txt',
44     *          'contentType' => 'text/plain'
45     *      ],
46     *      'file2'     => [
47     *          'filename'    => 'test.pdf',
48     *          'contentType' => 'application/pdf',
49     *          'contents'    => file_get_contents(__DIR__ . '/path/to/test.pdf'
50     *      ]
51     *    ]
52     * @var array
53     */
54    protected array $data = [];
55
56    /**
57     * Query string
58     * @var ?string
59     */
60    protected ?string $queryString = null;
61
62    /**
63     * Common mime types
64     * @var array
65     */
66    protected static array $mimeTypes = [
67        'bmp'    => 'image/x-ms-bmp',
68        'bz2'    => 'application/bzip2',
69        'csv'    => 'text/csv',
70        'doc'    => 'application/msword',
71        'docx'   => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
72        'gif'    => 'image/gif',
73        'gz'     => 'application/gzip',
74        'jpe'    => 'image/jpeg',
75        'jpg'    => 'image/jpeg',
76        'jpeg'   => 'image/jpeg',
77        'json'   => 'application/json',
78        'log'    => 'text/plain',
79        'pdf'    => 'application/pdf',
80        'png'    => 'image/png',
81        'ppt'    => 'application/msword',
82        'pptx'   => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
83        'psd'    => 'image/x-photoshop',
84        'svg'    => 'image/svg+xml',
85        'tar'    => 'application/x-tar',
86        'tbz'    => 'application/bzip2',
87        'tbz2'   => 'application/bzip2',
88        'tgz'    => 'application/gzip',
89        'tif'    => 'image/tiff',
90        'tiff'   => 'image/tiff',
91        'tsv'    => 'text/tsv',
92        'txt'    => 'text/plain',
93        'xls'    => 'application/msword',
94        'xlsx'   => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
95        'xml'    => 'application/xml',
96        'zip'    => 'application/zip'
97    ];
98
99    /**
100     * Default mime type
101     * @var string
102     */
103    protected static string $defaultMimeType = 'application/octet-stream';
104
105    /**
106     * Constructor
107     *
108     * Instantiate the request data object
109     *
110     * @param array $data
111     */
112    public function __construct(array $data = [], mixed $filters = null)
113    {
114        if ($filters !== null) {
115            if (is_array($filters)) {
116                $this->addFilters($filters);
117            } else {
118                $this->addFilter($filters);
119            }
120        }
121
122        $this->setData($data);
123    }
124
125    /**
126     * Set data
127     *
128     * @param  array|string $data
129     * @return Data
130     */
131    public function setData(array|string $data): Data
132    {
133        if (is_string($data)) {
134            $this->data = [self::POP_CLIENT_REQUEST_RAW_DATA => $data];
135        } else if (is_array($data) && (count($data) == 1) && isset($data[0])) {
136            $this->data = [self::POP_CLIENT_REQUEST_RAW_DATA => $data[0]];
137        } else {
138            $this->data = $data;
139            $this->prepareQueryString();
140        }
141
142        return $this;
143    }
144
145    /**
146     * Add data
147     *
148     * @param  array|string $data
149     * @param  mixed        $value
150     * @return Data
151     */
152    public function addData(array|string $data, mixed $value = null): Data
153    {
154        if (is_string($data) && ($value !== null)) {
155            $this->data[$data] = $value;
156        } else if (is_array($data)) {
157            $this->data = array_merge($this->data, $data);
158        }
159
160        $this->prepareQueryString();
161
162        return $this;
163    }
164
165    /**
166     * Get data
167     *
168     * @param  ?string $key
169     * @return mixed
170     */
171    public function getData(?string $key = null): mixed
172    {
173        if ($key !== null) {
174            return $this->data[$key] ?? null;
175        } else {
176            return $this->data;
177        }
178    }
179
180    /**
181     * Has data
182     *
183     * @param  ?string $key
184     * @return bool
185     */
186    public function hasData(?string $key = null): bool
187    {
188        if ($key !== null) {
189            return (isset($this->data[$key]));
190        } else {
191            return !empty($this->data);
192        }
193    }
194
195    /**
196     * Remove data
197     *
198     * @param  string $key
199     * @return Data
200     */
201    public function removeData(string $key): Data
202    {
203        if (isset($this->data[$key])) {
204            unset($this->data[$key]);
205        }
206
207        $this->prepareQueryString();
208
209        return $this;
210    }
211
212    /**
213     * Remove all data
214     *
215     * @return Data
216     */
217    public function removeAllData(): Data
218    {
219        $this->data        = [];
220        $this->queryString = null;
221
222        return $this;
223    }
224
225    /**
226     * Prepare the query string
227     *
228     * @param  array $queryData
229     * @param  bool  $withQuestionMark
230     * @return string|null
231     */
232    public function prepareQueryString(array $queryData = [], bool $withQuestionMark = false): string|null
233    {
234        if (!array_key_exists(self::POP_CLIENT_REQUEST_RAW_DATA, $this->data) && (!empty($this->data) || !empty($queryData))) {
235            $data = array_merge($this->data, $queryData);
236            if ($this->hasFilters()) {
237                $data = $this->filter($data);
238            }
239            $this->queryString = http_build_query($data);
240        } else {
241            $this->queryString = null;
242        }
243
244        return ($withQuestionMark) ? '?' . $this->queryString : $this->queryString;
245    }
246
247    /**
248     * Is query string prepared
249     *
250     * @return bool
251     */
252    public function hasQueryString(): bool
253    {
254        return ($this->queryString !== null);
255    }
256
257    /**
258     * Get the query string
259     *
260     * @param  array $queryData
261     * @param  bool  $withQuestionMark
262     * @return string
263     */
264    public function getQueryString(array $queryData = [], bool $withQuestionMark = false): string
265    {
266        return $this->prepareQueryString($queryData, $withQuestionMark);
267    }
268
269    /**
270     * Get query string length
271     *
272     * @param  bool $mb
273     * @return int
274     */
275    public function getQueryStringLength(bool $mb = false): int
276    {
277        return ($mb) ? mb_strlen($this->queryString) : strlen($this->queryString);
278    }
279
280    /**
281     * Get raw data
282     *
283     * @return string|null
284     */
285    public function getRawData(): string|null
286    {
287        return $this->data[self::POP_CLIENT_REQUEST_RAW_DATA] ?? null;
288    }
289
290    /**
291     * Has raw data
292     *
293     * @return bool
294     */
295    public function hasRawData(): bool
296    {
297        return (count($this->data) == 1) && isset($this->data[self::POP_CLIENT_REQUEST_RAW_DATA]);
298    }
299
300    /**
301     * Get raw data length
302     *
303     * @param  bool $mb
304     * @return int
305     */
306    public function getRawDataLength(bool $mb = false): int
307    {
308        return ($mb) ? mb_strlen((string)$this->getRawData()) : strlen((string)$this->getRawData());
309    }
310
311    /**
312     * Get common mime types
313     *
314     * @return array
315     */
316    public static function getMimeTypes(): array
317    {
318        return static::$mimeTypes;
319    }
320
321    /**
322     * Has mime type
323     *
324     * @param  string $ext
325     * @return bool
326     */
327    public static function hasMimeType(string $ext): bool
328    {
329        return isset(static::$mimeTypes[$ext]);
330    }
331
332    /**
333     * Get mime type
334     *
335     * @param  string $ext
336     * @return string|null
337     */
338    public static function getMimeType(string $ext): string|null
339    {
340        return static::$mimeTypes[$ext] ?? null;
341    }
342
343    /**
344     * Get mime type
345     *
346     * @param  string $filename
347     * @return string
348     */
349    public static function getMimeTypeFromFilename(string $filename): string
350    {
351        $info = pathinfo($filename);
352
353        return (isset($info['extension']) && isset(self::$mimeTypes[$info['extension']])) ?
354            self::$mimeTypes[$info['extension']] : self::$defaultMimeType;
355    }
356
357    /**
358     * Get default mime type
359     *
360     * @return string
361     */
362    public static function getDefaultMimeType(): string
363    {
364        return static::$defaultMimeType;
365    }
366
367}