FileUpload::decodeServerOptions()   B
last analyzed

Complexity

Conditions 6
Paths 5

Size

Total Lines 21

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 21
rs 8.9617
c 0
b 0
f 0
cc 6
nc 5
nop 1
1
<?php
2
3
namespace yiicod\fileupload\widgets;
4
5
use Exception;
6
use Yii;
7
use yii\helpers\ArrayHelper;
8
use yii\helpers\HtmlPurifier;
9
use yii\helpers\Url;
10
use yii\widgets\InputWidget;
11
use yiicod\fileupload\components\base\UploaderInterface;
12
use yiicod\fileupload\themes\base\BaseTheme;
13
use yiicod\fileupload\themes\ThemeInterface;
14
15
/**
16
 * Class FileUpload
17
 * File upload widget
18
 *
19
 * @author Alexey Orlov
20
 * @author Virchenko Maksim <[email protected]>
21
 *
22
 * @package yiicod\fileupload\widgets
23
 */
24
class FileUpload extends InputWidget
25
{
26
    /**
27
     * Widget id.
28
     *
29
     * @var string
30
     */
31
    public $id = 'fileupload';
32
33
    /**
34
     * Theme class
35
     *
36
     * @var string|array
37
     */
38
    public $theme = BaseTheme::class;
39
40
    /**
41
     * Html options.
42
     *
43
     * @var array
44
     */
45
    public $options = [];
46
47
    /**
48
     * Upload url
49
     *
50
     * @var string
51
     */
52
    public $uploadUrl = 'site/file-upload';
53
54
    /**
55
     * Remove url
56
     *
57
     * @var string
58
     */
59
    public $deleteUrl = 'site/file-delete';
60
61
    /**
62
     * Class name
63
     *
64
     * @var UploaderInterface string
65
     */
66
    public $uploader;
67
68
    /**
69
     * User data, send in receptorClass method.
70
     *
71
     * @var array
72
     */
73
    public $userData = [];
74
75
    /**
76
     * Run widget
77
     */
78
    public function run()
79
    {
80
        $theme = $this->buildTheme();
81
        $this->registerClientScripts();
82
        $theme->registerClientScripts();
83
84
        return $this->render($theme->getViewAlias(), ArrayHelper::merge($theme->getViewData(), [
85
            'id' => $this->id,
86
            'model' => $this->model,
87
            'attribute' => $this->attribute,
88
            'options' => $this->generateHtmlOptions(),
89
        ]));
90
    }
91
92
    /**
93
     * Get theme
94
     *
95
     * @return ThemeInterface
96
     *
97
     * @throws Exception
98
     */
99
    protected function buildTheme(): ThemeInterface
100
    {
101
        $theme = null;
102
103
        if (is_a($this->theme, ThemeInterface::class)) {
104
            $theme = $this->theme;
105
        } elseif (is_array($this->theme)) {
106
            if (isset($this->theme['class']) && in_array(ThemeInterface::class, class_implements($this->theme['class']))) {
107
                $theme = new $this->theme['class']($this);
108
109
                foreach ($this->theme as $option => $value) {
110
                    if (property_exists($theme, $option)) {
111
                        $theme->{$option} = $value;
112
                    }
113
                }
114
            }
115
        } elseif ($this->theme && in_array(ThemeInterface::class, class_implements($this->theme))) {
116
            $theme = new $this->theme($this);
117
        }
118
119
        if (is_null($theme)) {
120
            throw new Exception(sprintf('Theme must be string of className or array("class" => className) ' .
121
                'and implement "%s"', ThemeInterface::class));
122
        }
123
124
        /* @var ThemeInterface $theme */
125
        return $theme;
126
    }
127
128
    /**
129
     * Generate html options for widget.
130
     *
131
     * @return array
132
     */
133
    public function generateHtmlOptions(): array
134
    {
135
        $this->options['id'] = $this->id;
136
137
        return $this->options;
138
    }
139
140
    /**
141
     * Generate upload url.
142
     *
143
     * @param string $url
144
     *
145
     * @return string
146
     */
147
    public function generateUrl(?string $url): ?string
148
    {
149
        if (is_null($url)) {
150
            return null;
151
        }
152
153
        $payload = self::encodeServerOptions([
154
            'uploader' => $this->uploader,
155
            'userData' => $this->userData,
156
        ]);
157
158
        if (is_array($url)) {
159
            return Url::to(ArrayHelper::merge($url, ['data' => $payload]), true);
160
        }
161
162
        return Url::to([$url, 'data' => $payload], true);
163
    }
164
165
    /**
166
     * Decode server options.
167
     *
168
     * @param string $data Data key for decode server options
169
     *
170
     * @return array $data Return array of data
171
     *
172
     * @throws Exception
173
     */
174
    public static function decodeServerOptions($data): array
175
    {
176
        $vars = Yii::$app->session->get($data);
177
178
        if (false === $vars && isset($_FILES['files'])) {
179
            throw new Exception('Incorrect file/files', 406);
180
        }
181
182
        $vars = @unserialize(HtmlPurifier::process(base64_decode($vars)));
183
        if (false === $vars) {
184
            throw new Exception('Your session was expired. Please reload your page and try again.', 400);
185
        }
186
187
        foreach ($vars['userData'] as $key => $value) {
188
            if ('?' === $value) {
189
                $vars['userData'][$key] = HtmlPurifier::process(Yii::$app->request->getQueryParam($key, null));
190
            }
191
        }
192
193
        return $vars;
194
    }
195
196
    /**
197
     * Encode server options.
198
     *
199
     * @return string $data Return encode array of data
200
     *
201
     * @param array $data Server options for uploader
202
     *
203
     * @throws Exception
204
     */
205
    public static function encodeServerOptions($data): string
206
    {
207
        $data = base64_encode(serialize($data));
208
209
        Yii::$app->session->set(md5($data), $data);
210
211
        return md5($data);
212
    }
213
214
    /**
215
     * Register client scripts
216
     */
217
    protected function registerClientScripts()
218
    {
219
        FileUploadJsAsset::register($this->getView());
220
        FileUploadCssAsset::register($this->getView());
221
    }
222
}
223