Commit | Line | Data |
---|---|---|
5b0a72f1 TD |
1 | acp/update_com.woltlab.wcf_5.4_session_1_cookies.php\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00000770\00001750\00000056\000000011660\014043741472\0023050\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0timwolla\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0plugdev\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<?php |
2 | ||
3 | /** | |
4 | * Sets the new session cookies. | |
5 | * | |
6 | * @author Tim Duesterhus | |
7 | * @copyright 2001-2021 WoltLab GmbH | |
8 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
9 | * @package WoltLabSuite\Core | |
10 | */ | |
11 | ||
12 | use wcf\system\application\ApplicationHandler; | |
13 | use wcf\system\form\container\GroupFormElementContainer; | |
14 | use wcf\system\form\element\LabelFormElement; | |
15 | use wcf\system\form\FormDocument; | |
16 | use wcf\system\request\RouteHandler; | |
17 | use wcf\system\WCF; | |
18 | use wcf\util\CryptoUtil; | |
19 | use wcf\util\HeaderUtil; | |
20 | ||
21 | // 1) Check whether the cookies are already in place. | |
22 | $hasValidSessionCookie = false; | |
23 | if (!empty($_COOKIE[COOKIE_PREFIX . "user_session"])) { | |
24 | $cookieValue = CryptoUtil::getValueFromSignedString($_COOKIE[COOKIE_PREFIX . "user_session"]); | |
25 | if ($cookieValue && \mb_strlen($cookieValue, '8bit') === 22) { | |
26 | $sessionID = \bin2hex(\mb_substr($cookieValue, 1, 20, '8bit')); | |
27 | if ($sessionID === WCF::getSession()->sessionID) { | |
28 | $hasValidSessionCookie = true; | |
29 | } | |
30 | } | |
31 | } | |
32 | ||
33 | $hasValidXsrfToken = false; | |
34 | if (!empty($_COOKIE['XSRF-TOKEN'])) { | |
35 | if ( | |
36 | // Check that the XSRF-TOKEN cookie is correctly signed. | |
37 | CryptoUtil::validateSignedString($_COOKIE['XSRF-TOKEN']) | |
38 | // Check that the current session value matches the cookie value. | |
39 | && WCF::getSession()->checkSecurityToken($_COOKIE['XSRF-TOKEN']) | |
40 | // Check that the 't' used for this request matches the cookie value. | |
41 | && ( | |
42 | !empty($_REQUEST['t']) | |
43 | && \hash_equals($_COOKIE['XSRF-TOKEN'], $_REQUEST['t']) | |
44 | ) | |
45 | ) { | |
46 | $hasValidXsrfToken = true; | |
47 | } | |
48 | } | |
49 | ||
50 | if ($hasValidSessionCookie && $hasValidXsrfToken) { | |
51 | // The process may continue; | |
52 | return; | |
53 | } | |
54 | ||
55 | // 2) Set new session cookie. | |
56 | HeaderUtil::setCookie( | |
57 | "user_session", | |
58 | CryptoUtil::createSignedString( | |
59 | \pack( | |
60 | 'CA20C', | |
61 | 1, | |
62 | \hex2bin(WCF::getSession()->sessionID), | |
63 | 0 | |
64 | ) | |
65 | ) | |
66 | ); | |
67 | ||
68 | // 3) Set new XSRF-TOKEN cookie. | |
69 | $sameSite = $cookieDomain = ''; | |
70 | if (ApplicationHandler::getInstance()->isMultiDomainSetup()) { | |
71 | // We need to specify the cookieDomain in a multi domain set-up, because | |
72 | // otherwise no cookies are sent to subdomains. | |
73 | $cookieDomain = HeaderUtil::getCookieDomain(); | |
74 | $cookieDomain = ($cookieDomain !== null ? '; domain=' . $cookieDomain : ''); | |
75 | } else { | |
76 | // SameSite=strict is not supported in a multi domain set-up, because | |
77 | // it breaks cross-application requests. | |
78 | $sameSite = '; SameSite=strict'; | |
79 | } | |
80 | ||
81 | do { | |
82 | $bytes = \bin2hex(\random_bytes(16)); | |
83 | } while (\strpos(\base64_encode($bytes), '+') !== false); | |
84 | $xsrfToken = CryptoUtil::createSignedString($bytes); | |
85 | WCF::getSession()->register('__SECURITY_TOKEN', $xsrfToken); | |
86 | \header( | |
87 | 'set-cookie: XSRF-TOKEN=' . \rawurlencode($xsrfToken) . '; path=/' . $cookieDomain . (RouteHandler::secureConnection() ? '; secure' : '') . $sameSite, | |
88 | false | |
89 | ); | |
90 | ||
91 | // 4) Adjust the SECURITY_TOKEN. | |
92 | $container = new GroupFormElementContainer(); | |
93 | if (WCF::getLanguage()->getFixedLanguageCode() === 'de') { | |
94 | $container->setLabel("Sitzungs-Vorbereitung"); | |
95 | $container->setDescription(''); | |
96 | } else { | |
97 | $container->setLabel("Session Preparation"); | |
98 | $container->setDescription(''); | |
99 | } | |
100 | ||
101 | $label = new LabelFormElement($container); | |
102 | if (WCF::getLanguage()->getFixedLanguageCode() === 'de') { | |
103 | $label->setLabel(''); | |
104 | $label->setText( | |
105 | <<<'EOT' | |
106 | WoltLab Suite 5.4 aktualisiert das Sitzungs-System. | |
107 | Dieser Schritt des Upgrades bereitet Ihre aktive Sitzung auf die Aktualisierung vor und stellt sicher, dass Sie dauerhaft eingeloggt bleiben. | |
108 | Falls Sie dieses Fenster nach dem Fortfahren erneut sehen, konnte Ihre Sitzung nicht vorbereitet werden. | |
109 | Bitte leeren Sie in diesem Fall die Cookies in Ihrem Webbrowser, melden sich erneut in der Administrationsoberfläche an und versuchen das Upgrade erneut. | |
110 | EOT | |
111 | ); | |
112 | } else { | |
113 | $label->setLabel(''); | |
114 | $label->setText( | |
115 | <<<'EOT' | |
116 | WoltLab Suite 5.4 updates the session handling. | |
117 | This step of the upgrade prepares your active session for this upgrade and ensures that you will continously stay logged in. | |
118 | If you see this window again after proceeding then your session could not be prepared. | |
119 | Please clear your web browser's cookies in this case. | |
120 | Afterwards log back into the Administrator's Control Panel and restart the upgrade. | |
121 | EOT | |
122 | ); | |
123 | } | |
124 | ||
125 | $label->setDescription( | |
126 | <<<EOT | |
127 | <script>(function() { | |
128 | var oldToken = SECURITY_TOKEN; | |
129 | SECURITY_TOKEN = encodeURIComponent("{$xsrfToken}"); | |
130 | var oldExecute = WCF.ACP.Package.Installation.prototype._executeStep; | |
131 | WCF.ACP.Package.Installation.prototype._executeStep = function (step, node, additionalData) { | |
132 | var request = this._proxy._ajaxRequest; | |
133 | request.setOption('url', request.getOption('url').replace(oldToken, SECURITY_TOKEN)); | |
134 | ||
135 | return oldExecute.call(this, step, node, additionalData); | |
136 | } | |
137 | })(); | |
138 | </script> | |
139 | EOT | |
140 | ); | |
141 | ||
142 | $container->appendChild($label); | |
143 | ||
144 | $document = new FormDocument("cookies_set"); | |
145 | $document->appendContainer($container); | |
146 | ||
147 | return $document; | |
148 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0acp/database/update_com.woltlab.wcf_5.4_session_2_user_session.php\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00000770\00001750\00000056\000000004173\014043741470\0025701\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0timwolla\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0plugdev\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<?php | |
149 | ||
150 | /** | |
151 | * Creates the user_session table. | |
152 | * | |
153 | * @author Tim Duesterhus | |
154 | * @copyright 2001-2020 WoltLab GmbH | |
155 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
156 | * @package WoltLabSuite\Core | |
157 | */ | |
158 | ||
159 | use wcf\system\database\table\column\CharDatabaseTableColumn; | |
160 | use wcf\system\database\table\column\IntDatabaseTableColumn; | |
161 | use wcf\system\database\table\column\MediumblobDatabaseTableColumn; | |
162 | use wcf\system\database\table\column\NotNullInt10DatabaseTableColumn; | |
163 | use wcf\system\database\table\column\NotNullVarchar255DatabaseTableColumn; | |
164 | use wcf\system\database\table\column\VarcharDatabaseTableColumn; | |
165 | use wcf\system\database\table\DatabaseTable; | |
166 | use wcf\system\database\table\index\DatabaseTableForeignKey; | |
167 | use wcf\system\database\table\index\DatabaseTableIndex; | |
168 | ||
169 | return [ | |
170 | DatabaseTable::create('wcf1_user_session') | |
171 | ->columns([ | |
172 | CharDatabaseTableColumn::create('sessionID') | |
173 | ->length(40) | |
174 | ->notNull(), | |
175 | IntDatabaseTableColumn::create('userID') | |
176 | ->length(10), | |
177 | NotNullVarchar255DatabaseTableColumn::create('userAgent') | |
178 | ->defaultValue(''), | |
179 | VarcharDatabaseTableColumn::create('ipAddress') | |
180 | ->length(39) | |
181 | ->defaultValue(''), | |
182 | NotNullInt10DatabaseTableColumn::create('creationTime'), | |
183 | NotNullInt10DatabaseTableColumn::create('lastActivityTime') | |
184 | ->defaultValue(0), | |
185 | MediumblobDatabaseTableColumn::create('sessionVariables'), | |
186 | ]) | |
187 | ->indices([ | |
188 | DatabaseTableIndex::create() | |
189 | ->type(DatabaseTableIndex::PRIMARY_TYPE) | |
190 | ->columns(['sessionID']), | |
191 | DatabaseTableIndex::create() | |
192 | ->columns(['userID']), | |
193 | DatabaseTableIndex::create() | |
194 | ->columns(['lastActivityTime']), | |
195 | ]) | |
196 | ->foreignKeys([ | |
197 | DatabaseTableForeignKey::create() | |
198 | ->columns(['userID']) | |
199 | ->referencedTable('wcf1_user') | |
200 | ->referencedColumns(['userID']) | |
201 | ->onDelete('CASCADE'), | |
202 | ]), | |
203 | ]; | |
204 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0acp/update_com.woltlab.wcf_5.4_session_3_migrate_session.php\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00000770\00001750\00000056\000000003115\014043741472\0024605\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0timwolla\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0plugdev\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<?php | |
205 | ||
206 | /** | |
207 | * Creates a 5.4+ session matching the current ACP session. | |
208 | * | |
209 | * @author Tim Duesterhus | |
210 | * @copyright 2001-2020 WoltLab GmbH | |
211 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
212 | * @package WoltLabSuite\Core | |
213 | */ | |
214 | ||
215 | use wcf\system\session\SessionHandler; | |
216 | use wcf\system\WCF; | |
217 | ||
218 | $sql = "SELECT userID | |
219 | FROM wcf" . WCF_N . "_user_session | |
220 | WHERE sessionID = ?"; | |
221 | $statement = WCF::getDB()->prepareStatement($sql); | |
222 | $statement->execute([ | |
223 | SessionHandler::getInstance()->sessionID, | |
224 | ]); | |
225 | ||
226 | // Check if a matching session already exists. | |
227 | if ($statement->fetchSingleColumn() == SessionHandler::getInstance()->userID) { | |
228 | return; | |
229 | } | |
230 | ||
231 | $sql = "INSERT INTO wcf" . WCF_N . "_user_session | |
232 | (sessionID, userID, userAgent, ipAddress, creationTime, lastActivityTime, sessionVariables) | |
233 | VALUES (?, ?, ?, ?, ?, ?, ?)"; | |
234 | $statement = WCF::getDB()->prepareStatement($sql); | |
235 | ||
236 | $klass = new \ReflectionClass(SessionHandler::getInstance()); | |
237 | $property = $klass->getProperty('variables'); | |
238 | $property->setAccessible(true); | |
239 | $variables = $property->getValue(SessionHandler::getInstance()); | |
240 | ||
241 | $variables[SessionHandler::class . "\0__reauthentication__"] = [ | |
242 | 'lastAuthentication' => TIME_NOW, | |
243 | 'lastCheck' => TIME_NOW, | |
244 | ]; | |
245 | ||
246 | $statement->execute([ | |
247 | SessionHandler::getInstance()->sessionID, | |
248 | SessionHandler::getInstance()->userID, | |
249 | SessionHandler::getInstance()->userAgent, | |
250 | SessionHandler::getInstance()->ipAddress, | |
251 | TIME_NOW, | |
252 | TIME_NOW, | |
253 | \serialize([ | |
254 | 'acp' => $variables, | |
255 | 'frontend' => [], | |
256 | ]), | |
257 | ]); | |
258 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0lib/util/HeaderUtil.class.php\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00000770\00001750\00000056\000000014624\014043741532\0016534\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0timwolla\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0plugdev\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<?php | |
259 | ||
260 | namespace wcf\util; | |
261 | ||
262 | use wcf\system\application\ApplicationHandler; | |
263 | use wcf\system\event\EventHandler; | |
264 | use wcf\system\request\RequestHandler; | |
265 | use wcf\system\request\RouteHandler; | |
266 | use wcf\system\session\SessionHandler; | |
267 | use wcf\system\WCF; | |
268 | ||
269 | /** | |
270 | * Contains header-related functions. | |
271 | * | |
272 | * @author Marcel Werk | |
273 | * @copyright 2001-2019 WoltLab GmbH | |
274 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
275 | * @package WoltLabSuite\Core\Util | |
276 | */ | |
277 | final class HeaderUtil | |
278 | { | |
279 | /** | |
280 | * @deprecated 5.4 - gzip support was removed. | |
281 | */ | |
282 | const GZIP_LEVEL = 1; | |
283 | ||
284 | /** | |
285 | * output HTML | |
286 | * @var string | |
287 | */ | |
288 | public static $output = ''; | |
289 | ||
290 | /** | |
291 | * Alias to php setcookie() function. | |
292 | * | |
293 | * @param string $name | |
294 | * @param string $value | |
295 | * @param int $expire | |
296 | */ | |
297 | public static function setCookie($name, $value = '', $expire = 0) | |
298 | { | |
299 | $cookieDomain = self::getCookieDomain(); | |
300 | ||
301 | @\header( | |
302 | 'Set-Cookie: ' . \rawurlencode(COOKIE_PREFIX . $name) . '=' . \rawurlencode((string)$value) . ($expire ? '; expires=' . \gmdate( | |
303 | 'D, d-M-Y H:i:s', | |
304 | $expire | |
305 | ) . ' GMT; max-age=' . ($expire - TIME_NOW) : '') . '; path=/' . ($cookieDomain !== null ? '; domain=' . $cookieDomain : '') . (RouteHandler::secureConnection() ? '; secure' : '') . '; HttpOnly', | |
306 | false | |
307 | ); | |
308 | } | |
309 | ||
310 | /** | |
311 | * Returns the cookie domain for the active application or 'null' if no domain should be specified. | |
312 | */ | |
313 | public static function getCookieDomain(): ?string | |
314 | { | |
315 | $application = ApplicationHandler::getInstance()->getActiveApplication(); | |
316 | $addDomain = (\mb_strpos( | |
317 | $application->cookieDomain, | |
318 | '.' | |
319 | ) === false || StringUtil::endsWith( | |
320 | $application->cookieDomain, | |
321 | '.lan' | |
322 | ) || StringUtil::endsWith($application->cookieDomain, '.local')) ? false : true; | |
323 | ||
324 | if (!$addDomain) { | |
325 | return null; | |
326 | } | |
327 | ||
328 | $cookieDomain = $application->cookieDomain; | |
329 | if ($addDomain && \strpos($cookieDomain, ':') !== false) { | |
330 | $cookieDomain = \explode(':', $cookieDomain, 2)[0]; | |
331 | } | |
332 | ||
333 | return $cookieDomain; | |
334 | } | |
335 | ||
336 | /** | |
337 | * Sends the headers of a page. | |
338 | */ | |
339 | public static function sendHeaders() | |
340 | { | |
341 | // send content type | |
342 | @\header('Content-Type: text/html; charset=UTF-8'); | |
343 | ||
344 | // send no cache headers | |
345 | if (!PACKAGE_ID || !WCF::getSession()->spiderID) { | |
346 | self::sendNoCacheHeaders(); | |
347 | } | |
348 | ||
349 | // send X-Frame-Options | |
350 | if (HTTP_SEND_X_FRAME_OPTIONS) { | |
351 | @\header('X-Frame-Options: SAMEORIGIN'); | |
352 | } | |
353 | ||
354 | \ob_start([self::class, 'parseOutput']); | |
355 | } | |
356 | ||
357 | /** | |
358 | * Sends no cache headers. | |
359 | */ | |
360 | public static function sendNoCacheHeaders() | |
361 | { | |
362 | @\header('Last-Modified: ' . \gmdate('D, d M Y H:i:s') . ' GMT'); | |
363 | @\header('Cache-Control: max-age=0, no-cache, no-store, must-revalidate'); | |
364 | } | |
365 | ||
366 | /** | |
367 | * @deprecated 5.4 - This method is a no-op, as gzip support was removed. | |
368 | */ | |
369 | public static function exceptionDisableGzip() | |
370 | { | |
371 | } | |
372 | ||
373 | /** | |
374 | * Parses the rendered output. | |
375 | * | |
376 | * @param string $output | |
377 | * @return string | |
378 | */ | |
379 | public static function parseOutput($output) | |
380 | { | |
381 | self::$output = $output; | |
382 | ||
383 | if (!PACKAGE_ID || RequestHandler::getInstance()->isACPRequest()) { | |
384 | // force javascript relocation | |
385 | self::$output = \preg_replace('~<script([^>]*)>~', '<script data-relocate="true"\\1>', self::$output); | |
386 | } | |
387 | ||
388 | // move script tags to the bottom of the page | |
389 | $javascript = []; | |
390 | self::$output = \preg_replace_callback( | |
391 | '~(?P<conditionBefore><!--\[IF [^<]+\s*)?<script data-relocate="true"(?P<script>.*?</script>\s*)(?P<conditionAfter><!\[ENDIF]-->\s*)?~s', | |
392 | static function ($matches) use (&$javascript) { | |
393 | $match = ''; | |
394 | if (isset($matches['conditionBefore'])) { | |
395 | $match .= $matches['conditionBefore']; | |
396 | } | |
397 | $match .= '<script' . $matches['script']; | |
398 | if (isset($matches['conditionAfter'])) { | |
399 | $match .= $matches['conditionAfter']; | |
400 | } | |
401 | ||
402 | $javascript[] = $match; | |
403 | ||
404 | return ''; | |
405 | }, | |
406 | self::$output | |
407 | ); | |
408 | ||
409 | self::$output = \str_replace( | |
410 | '<!-- JAVASCRIPT_RELOCATE_POSITION -->', | |
411 | \implode("\n", $javascript), | |
412 | self::$output | |
413 | ); | |
414 | ||
415 | // 3rd party plugins may differ the actual output before it is sent to the browser | |
416 | // please be aware, that $eventObj is not available here due to this being a static | |
417 | // class. Use HeaderUtil::$output to modify it. | |
418 | if (!\defined('NO_IMPORTS')) { | |
419 | EventHandler::getInstance()->fireAction(self::class, 'parseOutput'); | |
420 | } | |
421 | ||
422 | return self::$output; | |
423 | } | |
424 | ||
425 | /** | |
426 | * Redirects the user agent to given location. | |
427 | * | |
428 | * @param string $location | |
429 | * @param bool $sendStatusCode | |
430 | * @param bool $temporaryRedirect | |
431 | */ | |
432 | public static function redirect($location, $sendStatusCode = false, $temporaryRedirect = true) | |
433 | { | |
434 | // https://github.com/WoltLab/WCF/issues/2568 | |
435 | if (SessionHandler::getInstance()->isFirstVisit()) { | |
436 | SessionHandler::getInstance()->register('__wcfIsFirstVisit', true); | |
437 | } | |
438 | ||
439 | if ($sendStatusCode) { | |
440 | if ($temporaryRedirect) { | |
441 | @\header('HTTP/1.1 307 Temporary Redirect'); | |
442 | } else { | |
443 | @\header('HTTP/1.1 301 Moved Permanently'); | |
444 | } | |
445 | } | |
446 | ||
447 | \header('Location: ' . $location); | |
448 | } | |
449 | ||
450 | /** | |
451 | * Does a delayed redirect. | |
452 | * | |
453 | * @param string $location | |
454 | * @param string $message | |
455 | * @param int $delay | |
456 | * @param string $status | |
457 | */ | |
458 | public static function delayedRedirect($location, $message, $delay = 5, $status = 'success') | |
459 | { | |
460 | WCF::getTPL()->assign([ | |
461 | 'url' => $location, | |
462 | 'message' => $message, | |
463 | 'wait' => $delay, | |
464 | 'templateName' => 'redirect', | |
465 | 'templateNameApplication' => 'wcf', | |
466 | 'status' => $status, | |
467 | ]); | |
468 | WCF::getTPL()->display('redirect'); | |
469 | } | |
470 | ||
471 | /** | |
472 | * Forbid creation of HeaderUtil objects. | |
473 | */ | |
474 | private function __construct() | |
475 | { | |
476 | // does nothing | |
477 | } | |
478 | } | |
479 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0lib/system/package/plugin/AbstractPackageInstallationPlugin.class.php\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00000770\00001750\00000056\000000006165\014043741530\0026525\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0timwolla\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0plugdev\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<?php | |
480 | ||
481 | namespace wcf\system\package\plugin; | |
482 | ||
483 | use wcf\system\event\EventHandler; | |
484 | use wcf\system\package\PackageArchive; | |
485 | use wcf\system\package\PackageInstallationDispatcher; | |
486 | use wcf\system\WCF; | |
487 | ||
488 | /** | |
489 | * Abstract implementation of a package installation plugin. | |
490 | * | |
491 | * @author Alexander Ebert | |
492 | * @copyright 2001-2019 WoltLab GmbH | |
493 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
494 | * @package WoltLabSuite\Core\System\Package\Plugin | |
495 | */ | |
496 | abstract class AbstractPackageInstallationPlugin implements IPackageInstallationPlugin | |
497 | { | |
498 | /** | |
499 | * table application prefix | |
500 | * @var string | |
501 | */ | |
502 | public $application = 'wcf'; | |
503 | ||
504 | /** | |
505 | * database table name | |
506 | * @var string | |
507 | */ | |
508 | public $tableName = ''; | |
509 | ||
510 | /** | |
511 | * active instance of PackageInstallationDispatcher | |
512 | * @var PackageInstallationDispatcher | |
513 | */ | |
514 | public $installation; | |
515 | ||
516 | /** | |
517 | * install/update instructions | |
518 | * @var array | |
519 | */ | |
520 | public $instruction = []; | |
521 | ||
522 | /** | |
523 | * Creates a new AbstractPackageInstallationPlugin object. | |
524 | * | |
525 | * @param PackageInstallationDispatcher $installation | |
526 | * @param array $instruction | |
527 | */ | |
528 | public function __construct(PackageInstallationDispatcher $installation, $instruction = []) | |
529 | { | |
530 | $this->installation = $installation; | |
531 | $this->instruction = $instruction; | |
532 | ||
533 | // call 'construct' event | |
534 | EventHandler::getInstance()->fireAction($this, 'construct'); | |
535 | } | |
536 | ||
537 | /** | |
538 | * @inheritDoc | |
539 | */ | |
540 | public function install() | |
541 | { | |
542 | // call 'install' event | |
543 | EventHandler::getInstance()->fireAction($this, 'install'); | |
544 | } | |
545 | ||
546 | /** | |
547 | * @inheritDoc | |
548 | */ | |
549 | public function update() | |
550 | { | |
551 | // call 'update' event | |
552 | EventHandler::getInstance()->fireAction($this, 'update'); | |
553 | ||
554 | return $this->install(); | |
555 | } | |
556 | ||
557 | /** | |
558 | * @inheritDoc | |
559 | */ | |
560 | public function hasUninstall() | |
561 | { | |
562 | // call 'hasUninstall' event | |
563 | EventHandler::getInstance()->fireAction($this, 'hasUninstall'); | |
564 | ||
565 | $sql = "SELECT COUNT(*) | |
566 | FROM " . $this->application . WCF_N . "_" . $this->tableName . " | |
567 | WHERE packageID = ?"; | |
568 | $statement = WCF::getDB()->prepareStatement($sql); | |
569 | $statement->execute([$this->installation->getPackageID()]); | |
570 | ||
571 | return $statement->fetchSingleColumn() > 0; | |
572 | } | |
573 | ||
574 | /** | |
575 | * @inheritDoc | |
576 | */ | |
577 | public function uninstall() | |
578 | { | |
579 | // call 'uninstall' event | |
580 | EventHandler::getInstance()->fireAction($this, 'uninstall'); | |
581 | ||
582 | $sql = "DELETE FROM " . $this->application . WCF_N . "_" . $this->tableName . " | |
583 | WHERE packageID = ?"; | |
584 | $statement = WCF::getDB()->prepareStatement($sql); | |
585 | $statement->execute([$this->installation->getPackageID()]); | |
586 | } | |
587 | ||
588 | /** | |
589 | * @see \wcf\system\package\plugin\IPackageInstallationPlugin::getDefaultFilename() | |
590 | * @since 3.0 | |
591 | */ | |
592 | public static function getDefaultFilename() | |
593 | { | |
594 | return null; | |
595 | } | |
596 | ||
597 | /** | |
598 | * @inheritDoc | |
599 | */ | |
600 | public static function isValid(PackageArchive $archive, $instruction) | |
601 | { | |
602 | return true; | |
603 | } | |
604 | } | |
605 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0lib/system/package/plugin/DatabasePackageInstallationPlugin.class.php\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00000770\00001750\00000056\000000006030\014043741530\0026455\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0timwolla\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0plugdev\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<?php | |
606 | ||
607 | namespace wcf\system\package\plugin; | |
608 | ||
609 | use wcf\system\database\table\DatabaseTableChangeProcessor; | |
610 | use wcf\system\devtools\pip\IIdempotentPackageInstallationPlugin; | |
611 | use wcf\system\WCF; | |
612 | use wcf\util\FileUtil; | |
613 | ||
614 | /** | |
615 | * Executes individual database scripts during installation. | |
616 | * | |
617 | * @author Matthias Schmidt | |
618 | * @copyright 2001-2021 WoltLab GmbH | |
619 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
620 | * @package WoltLabSuite\Core\System\Package\Plugin | |
621 | */ | |
622 | class DatabasePackageInstallationPlugin extends AbstractPackageInstallationPlugin implements IIdempotentPackageInstallationPlugin | |
623 | { | |
624 | public const SCRIPT_DIR = 'acp/database/'; | |
625 | ||
626 | /** | |
627 | * @inheritDoc | |
628 | */ | |
629 | public function install() | |
630 | { | |
631 | parent::install(); | |
632 | ||
633 | $abbreviation = 'wcf'; | |
634 | $path = ''; | |
635 | if (isset($this->instruction['attributes']['application'])) { | |
636 | $abbreviation = $this->instruction['attributes']['application']; | |
637 | } elseif ($this->installation->getPackage()->isApplication) { | |
638 | $path = FileUtil::getRealPath(WCF_DIR . $this->installation->getPackage()->packageDir); | |
639 | } | |
640 | ||
641 | if (empty($path)) { | |
642 | $dirConstant = \strtoupper($abbreviation) . '_DIR'; | |
643 | if (!\defined($dirConstant)) { | |
644 | throw new \InvalidArgumentException("Cannot execute database PIP, abbreviation '{$abbreviation}' is unknown."); | |
645 | } | |
646 | ||
647 | $path = \constant($dirConstant); | |
648 | } | |
649 | ||
650 | $scriptPath = $path . $this->instruction['value']; | |
651 | ||
652 | $this->updateDatabase($scriptPath); | |
653 | ||
654 | if (@\unlink($scriptPath)) { | |
655 | $sql = "DELETE FROM wcf" . WCF_N . "_package_installation_file_log | |
656 | WHERE packageID = ? | |
657 | AND filename = ?"; | |
658 | $statement = WCF::getDB()->prepareStatement($sql); | |
659 | $statement->execute([ | |
660 | $this->installation->getPackageID(), | |
661 | $this->instruction['value'], | |
662 | ]); | |
663 | } | |
664 | } | |
665 | ||
666 | /** | |
667 | * Runs the database script at the given path. | |
668 | * | |
669 | * @param string $scriptPath | |
670 | */ | |
671 | private function updateDatabase(string $scriptPath): void | |
672 | { | |
673 | $tables = include($scriptPath); | |
674 | if (!\is_array($tables)) { | |
675 | throw new \UnexpectedValueException("A database script must return an array."); | |
676 | } | |
677 | ||
678 | (new DatabaseTableChangeProcessor( | |
679 | $this->installation->getPackage(), | |
680 | $tables, | |
681 | WCF::getDB()->getEditor() | |
682 | ))->process(); | |
683 | } | |
684 | ||
685 | /** | |
686 | * @inheritDoc | |
687 | */ | |
688 | public function hasUninstall() | |
689 | { | |
690 | // Database scripts cannot be uninstalled. | |
691 | return false; | |
692 | } | |
693 | ||
694 | /** | |
695 | * @inheritDoc | |
696 | */ | |
697 | public function uninstall() | |
698 | { | |
699 | // does nothing | |
700 | } | |
701 | ||
702 | /** | |
703 | * @inheritDoc | |
704 | */ | |
705 | public static function getDefaultFilename() | |
706 | { | |
707 | return static::SCRIPT_DIR . '*.php'; | |
708 | } | |
709 | ||
710 | /** | |
711 | * @inheritDoc | |
712 | */ | |
713 | public static function getSyncDependencies() | |
714 | { | |
715 | return ['file']; | |
716 | } | |
717 | } | |
718 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0lib/system/package/plugin/FilePackageInstallationPlugin.class.php\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00000770\00001750\00000056\000000011740\014043741530\0025634\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0timwolla\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0plugdev\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<?php | |
719 | ||
720 | namespace wcf\system\package\plugin; | |
721 | ||
722 | use wcf\data\application\Application; | |
723 | use wcf\data\package\Package; | |
724 | use wcf\system\devtools\pip\IIdempotentPackageInstallationPlugin; | |
725 | use wcf\system\exception\SystemException; | |
726 | use wcf\system\package\FilesFileHandler; | |
727 | use wcf\system\package\PackageArchive; | |
728 | use wcf\system\package\PackageInstallationDispatcher; | |
729 | use wcf\system\style\StyleHandler; | |
730 | use wcf\system\WCF; | |
731 | ||
732 | /** | |
733 | * Installs, updates and deletes files. | |
734 | * | |
735 | * @author Matthias Schmidt, Marcel Werk | |
736 | * @copyright 2001-2019 WoltLab GmbH | |
737 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
738 | * @package WoltLabSuite\Core\System\Package\Plugin | |
739 | */ | |
740 | class FilePackageInstallationPlugin extends AbstractPackageInstallationPlugin implements | |
741 | IIdempotentPackageInstallationPlugin | |
742 | { | |
743 | /** | |
744 | * @inheritDoc | |
745 | */ | |
746 | public $tableName = 'package_installation_file_log'; | |
747 | ||
748 | /** | |
749 | * @inheritDoc | |
750 | */ | |
751 | public function install() | |
752 | { | |
753 | parent::install(); | |
754 | ||
755 | $abbreviation = 'wcf'; | |
756 | if (isset($this->instruction['attributes']['application'])) { | |
757 | $abbreviation = $this->instruction['attributes']['application']; | |
758 | } elseif ($this->installation->getPackage()->isApplication) { | |
759 | $abbreviation = Package::getAbbreviation($this->installation->getPackage()->package); | |
760 | } | |
761 | ||
762 | // absolute path to package dir | |
763 | $packageDir = Application::getDirectory($abbreviation); | |
764 | ||
765 | // extract files.tar to temp folder | |
766 | $sourceFile = $this->installation->getArchive()->extractTar($this->instruction['value'], 'files_'); | |
767 | ||
768 | // create file handler | |
769 | $fileHandler = new FilesFileHandler($this->installation, $abbreviation); | |
770 | ||
771 | // extract content of files.tar | |
772 | $fileInstaller = $this->installation->extractFiles($packageDir, $sourceFile, $fileHandler); | |
773 | ||
774 | // if this is an application, write config.inc.php for this package | |
775 | if ( | |
776 | $this->installation->getPackage()->isApplication == 1 | |
777 | && $this->installation->getPackage()->package != 'com.woltlab.wcf' | |
778 | && $this->installation->getAction() == 'install' | |
779 | && $abbreviation != 'wcf' | |
780 | ) { | |
781 | // touch file | |
782 | $fileInstaller->touchFile(PackageInstallationDispatcher::CONFIG_FILE); | |
783 | ||
784 | // create file | |
785 | Package::writeConfigFile($this->installation->getPackageID()); | |
786 | ||
787 | // log files | |
788 | $sql = "INSERT INTO wcf" . WCF_N . "_package_installation_file_log | |
789 | (packageID, filename, application) | |
790 | VALUES (?, ?, ?)"; | |
791 | $statement = WCF::getDB()->prepareStatement($sql); | |
792 | $statement->execute([ | |
793 | $this->installation->getPackageID(), | |
794 | 'config.inc.php', | |
795 | Package::getAbbreviation($this->installation->getPackage()->package), | |
796 | ]); | |
797 | $statement->execute([ | |
798 | $this->installation->getPackageID(), | |
799 | PackageInstallationDispatcher::CONFIG_FILE, | |
800 | Package::getAbbreviation($this->installation->getPackage()->package), | |
801 | ]); | |
802 | ||
803 | // load application | |
804 | WCF::loadRuntimeApplication($this->installation->getPackageID()); | |
805 | } | |
806 | ||
807 | // delete temporary sourceArchive | |
808 | @\unlink($sourceFile); | |
809 | ||
810 | StyleHandler::resetStylesheets(true); | |
811 | } | |
812 | ||
813 | /** | |
814 | * @inheritDoc | |
815 | */ | |
816 | public function uninstall() | |
817 | { | |
818 | // fetch files from log | |
819 | $sql = "SELECT filename, application | |
820 | FROM wcf" . WCF_N . "_package_installation_file_log | |
821 | WHERE packageID = ?"; | |
822 | $statement = WCF::getDB()->prepareStatement($sql); | |
823 | $statement->execute([$this->installation->getPackageID()]); | |
824 | $files = $statement->fetchMap('application', 'filename', false); | |
825 | ||
826 | foreach ($files as $application => $filenames) { | |
827 | /** @noinspection PhpUndefinedMethodInspection */ | |
828 | $this->installation->deleteFiles(Application::getDirectory($application), $filenames); | |
829 | ||
830 | // delete log entries | |
831 | parent::uninstall(); | |
832 | } | |
833 | } | |
834 | ||
835 | /** | |
836 | * @inheritDoc | |
837 | */ | |
838 | public static function getDefaultFilename() | |
839 | { | |
840 | return 'files.tar'; | |
841 | } | |
842 | ||
843 | /** | |
844 | * @inheritDoc | |
845 | */ | |
846 | public static function isValid(PackageArchive $archive, $instruction) | |
847 | { | |
848 | if (!$instruction) { | |
849 | $instruction = static::getDefaultFilename(); | |
850 | } | |
851 | ||
852 | if (\preg_match('~\.(tar(\.gz)?|tgz)$~', $instruction)) { | |
853 | // check if file actually exists | |
854 | try { | |
855 | if ($archive->getTar()->getIndexByFilename($instruction) === false) { | |
856 | return false; | |
857 | } | |
858 | } catch (SystemException $e) { | |
859 | return false; | |
860 | } | |
861 | ||
862 | return true; | |
863 | } | |
864 | ||
865 | return false; | |
866 | } | |
867 | ||
868 | /** | |
869 | * @inheritDoc | |
870 | */ | |
871 | public static function getSyncDependencies() | |
872 | { | |
873 | return ['option']; | |
874 | } | |
875 | } | |
876 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0lib/system/package/plugin/ScriptPackageInstallationPlugin.class.php\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\00000770\00001750\00000056\000000005426\014043741531\0026226\0 0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0ustar \0timwolla\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0plugdev\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0<?php | |
877 | ||
878 | namespace wcf\system\package\plugin; | |
879 | ||
880 | use wcf\system\cache\CacheHandler; | |
881 | use wcf\system\exception\SystemException; | |
882 | use wcf\system\form\FormDocument; | |
883 | use wcf\system\WCF; | |
884 | use wcf\util\FileUtil; | |
885 | ||
886 | /** | |
887 | * Executes individual PHP scripts during installation. | |
888 | * | |
889 | * @author Alexander Ebert | |
890 | * @copyright 2001-2019 WoltLab GmbH | |
891 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
892 | * @package WoltLabSuite\Core\System\Package\Plugin | |
893 | */ | |
894 | class ScriptPackageInstallationPlugin extends AbstractPackageInstallationPlugin | |
895 | { | |
896 | /** | |
897 | * @inheritDoc | |
898 | */ | |
899 | public function install() | |
900 | { | |
901 | parent::install(); | |
902 | ||
903 | $abbreviation = 'wcf'; | |
904 | $path = ''; | |
905 | if (isset($this->instruction['attributes']['application'])) { | |
906 | $abbreviation = $this->instruction['attributes']['application']; | |
907 | } elseif ($this->installation->getPackage()->isApplication) { | |
908 | $path = FileUtil::getRealPath(WCF_DIR . $this->installation->getPackage()->packageDir); | |
909 | } | |
910 | ||
911 | if (empty($path)) { | |
912 | $dirConstant = \strtoupper($abbreviation) . '_DIR'; | |
913 | if (!\defined($dirConstant)) { | |
914 | throw new SystemException("Cannot execute script-PIP, abbreviation '" . $abbreviation . "' is unknown"); | |
915 | } | |
916 | ||
917 | $path = \constant($dirConstant); | |
918 | } | |
919 | ||
920 | $flushCache = true; | |
921 | if ( | |
922 | isset($this->instruction['attributes']['flushCache']) | |
923 | && $this->instruction['attributes']['flushCache'] === 'false' | |
924 | ) { | |
925 | $flushCache = false; | |
926 | } | |
927 | ||
928 | // reset WCF cache | |
929 | if ($flushCache) { | |
930 | CacheHandler::getInstance()->flushAll(); | |
931 | } | |
932 | ||
933 | // run script | |
934 | $result = $this->run($path . $this->instruction['value']); | |
935 | ||
936 | // delete script | |
937 | if (!($result instanceof FormDocument) && @\unlink($path . $this->instruction['value'])) { | |
938 | // delete file log entry | |
939 | $sql = "DELETE FROM wcf" . WCF_N . "_package_installation_file_log | |
940 | WHERE packageID = ? | |
941 | AND filename = ?"; | |
942 | $statement = WCF::getDB()->prepareStatement($sql); | |
943 | $statement->execute([ | |
944 | $this->installation->getPackageID(), | |
945 | $this->instruction['value'], | |
946 | ]); | |
947 | } | |
948 | ||
949 | return $result; | |
950 | } | |
951 | ||
952 | /** | |
953 | * Runs the script with the given path. | |
954 | * | |
955 | * @param string $scriptPath | |
956 | */ | |
957 | private function run($scriptPath) | |
958 | { | |
959 | return include($scriptPath); | |
960 | } | |
961 | ||
962 | /** | |
963 | * @inheritDoc | |
964 | */ | |
965 | public function hasUninstall() | |
966 | { | |
967 | // scripts can't be uninstalled | |
968 | return false; | |
969 | } | |
970 | ||
971 | /** | |
972 | * @inheritDoc | |
973 | */ | |
974 | public function uninstall() | |
975 | { | |
976 | // does nothing | |
977 | } | |
978 | } | |
979 | \0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0 |