Version Description
(2019-06-06) = * Update readme for tested up WP versions * Add check for replace function to get more solid replace for custom tables. #132 * Fix small typos * Fix Throwable because we set as minimum php 5.6
Download this release
Release Info
Developer | Bueltge |
Plugin | Search & Replace |
Version | 3.2.1 |
Comparing to | |
See all releases |
Code changes from version 3.2.0 to 3.2.1
- LICENSE +339 -674
- inc/Database/Exporter.php +713 -713
- inc/Database/Importer.php +64 -64
- inc/Database/Manager.php +200 -200
- inc/Database/Replace.php +431 -430
- inc/FileDownloader.php +374 -374
- inc/Page/AbstractPage.php +98 -98
- inc/Page/BackupDatabase.php +81 -81
- inc/Page/Credits.php +44 -44
- inc/Page/Manager.php +193 -193
- inc/Page/PageInterface.php +54 -54
- inc/Page/ReplaceDomain.php +112 -112
- inc/Page/SearchReplace.php +340 -340
- inc/Page/SqlImport.php +223 -223
- inc/Service/MaxExecutionTime.php +49 -49
- inc/templates/credits.php +138 -138
- inc/templates/db-backup.php +22 -22
- inc/templates/replace-domain.php +93 -93
- inc/templates/search-replace.php +110 -110
- inc/templates/sql-import.php +35 -35
- inpsyde-search-replace.php +129 -129
- readme.txt +154 -147
- vendor/autoload.php +1 -1
- vendor/composer/ClassLoader.php +1 -1
- vendor/composer/autoload_real.php +4 -4
- vendor/composer/autoload_static.php +4 -4
- vendor/composer/installed.json +72 -690
LICENSE
CHANGED
@@ -1,674 +1,339 @@
|
|
1 |
-
GNU GENERAL PUBLIC LICENSE
|
2 |
-
Version
|
3 |
-
|
4 |
-
Copyright (C)
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
software
|
12 |
-
|
13 |
-
|
14 |
-
to
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
GNU General Public License
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
authors
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
(
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
source code form), and must require no special password or key for
|
341 |
-
unpacking, reading or copying.
|
342 |
-
|
343 |
-
7. Additional Terms.
|
344 |
-
|
345 |
-
"Additional permissions" are terms that supplement the terms of this
|
346 |
-
License by making exceptions from one or more of its conditions.
|
347 |
-
Additional permissions that are applicable to the entire Program shall
|
348 |
-
be treated as though they were included in this License, to the extent
|
349 |
-
that they are valid under applicable law. If additional permissions
|
350 |
-
apply only to part of the Program, that part may be used separately
|
351 |
-
under those permissions, but the entire Program remains governed by
|
352 |
-
this License without regard to the additional permissions.
|
353 |
-
|
354 |
-
When you convey a copy of a covered work, you may at your option
|
355 |
-
remove any additional permissions from that copy, or from any part of
|
356 |
-
it. (Additional permissions may be written to require their own
|
357 |
-
removal in certain cases when you modify the work.) You may place
|
358 |
-
additional permissions on material, added by you to a covered work,
|
359 |
-
for which you have or can give appropriate copyright permission.
|
360 |
-
|
361 |
-
Notwithstanding any other provision of this License, for material you
|
362 |
-
add to a covered work, you may (if authorized by the copyright holders of
|
363 |
-
that material) supplement the terms of this License with terms:
|
364 |
-
|
365 |
-
a) Disclaiming warranty or limiting liability differently from the
|
366 |
-
terms of sections 15 and 16 of this License; or
|
367 |
-
|
368 |
-
b) Requiring preservation of specified reasonable legal notices or
|
369 |
-
author attributions in that material or in the Appropriate Legal
|
370 |
-
Notices displayed by works containing it; or
|
371 |
-
|
372 |
-
c) Prohibiting misrepresentation of the origin of that material, or
|
373 |
-
requiring that modified versions of such material be marked in
|
374 |
-
reasonable ways as different from the original version; or
|
375 |
-
|
376 |
-
d) Limiting the use for publicity purposes of names of licensors or
|
377 |
-
authors of the material; or
|
378 |
-
|
379 |
-
e) Declining to grant rights under trademark law for use of some
|
380 |
-
trade names, trademarks, or service marks; or
|
381 |
-
|
382 |
-
f) Requiring indemnification of licensors and authors of that
|
383 |
-
material by anyone who conveys the material (or modified versions of
|
384 |
-
it) with contractual assumptions of liability to the recipient, for
|
385 |
-
any liability that these contractual assumptions directly impose on
|
386 |
-
those licensors and authors.
|
387 |
-
|
388 |
-
All other non-permissive additional terms are considered "further
|
389 |
-
restrictions" within the meaning of section 10. If the Program as you
|
390 |
-
received it, or any part of it, contains a notice stating that it is
|
391 |
-
governed by this License along with a term that is a further
|
392 |
-
restriction, you may remove that term. If a license document contains
|
393 |
-
a further restriction but permits relicensing or conveying under this
|
394 |
-
License, you may add to a covered work material governed by the terms
|
395 |
-
of that license document, provided that the further restriction does
|
396 |
-
not survive such relicensing or conveying.
|
397 |
-
|
398 |
-
If you add terms to a covered work in accord with this section, you
|
399 |
-
must place, in the relevant source files, a statement of the
|
400 |
-
additional terms that apply to those files, or a notice indicating
|
401 |
-
where to find the applicable terms.
|
402 |
-
|
403 |
-
Additional terms, permissive or non-permissive, may be stated in the
|
404 |
-
form of a separately written license, or stated as exceptions;
|
405 |
-
the above requirements apply either way.
|
406 |
-
|
407 |
-
8. Termination.
|
408 |
-
|
409 |
-
You may not propagate or modify a covered work except as expressly
|
410 |
-
provided under this License. Any attempt otherwise to propagate or
|
411 |
-
modify it is void, and will automatically terminate your rights under
|
412 |
-
this License (including any patent licenses granted under the third
|
413 |
-
paragraph of section 11).
|
414 |
-
|
415 |
-
However, if you cease all violation of this License, then your
|
416 |
-
license from a particular copyright holder is reinstated (a)
|
417 |
-
provisionally, unless and until the copyright holder explicitly and
|
418 |
-
finally terminates your license, and (b) permanently, if the copyright
|
419 |
-
holder fails to notify you of the violation by some reasonable means
|
420 |
-
prior to 60 days after the cessation.
|
421 |
-
|
422 |
-
Moreover, your license from a particular copyright holder is
|
423 |
-
reinstated permanently if the copyright holder notifies you of the
|
424 |
-
violation by some reasonable means, this is the first time you have
|
425 |
-
received notice of violation of this License (for any work) from that
|
426 |
-
copyright holder, and you cure the violation prior to 30 days after
|
427 |
-
your receipt of the notice.
|
428 |
-
|
429 |
-
Termination of your rights under this section does not terminate the
|
430 |
-
licenses of parties who have received copies or rights from you under
|
431 |
-
this License. If your rights have been terminated and not permanently
|
432 |
-
reinstated, you do not qualify to receive new licenses for the same
|
433 |
-
material under section 10.
|
434 |
-
|
435 |
-
9. Acceptance Not Required for Having Copies.
|
436 |
-
|
437 |
-
You are not required to accept this License in order to receive or
|
438 |
-
run a copy of the Program. Ancillary propagation of a covered work
|
439 |
-
occurring solely as a consequence of using peer-to-peer transmission
|
440 |
-
to receive a copy likewise does not require acceptance. However,
|
441 |
-
nothing other than this License grants you permission to propagate or
|
442 |
-
modify any covered work. These actions infringe copyright if you do
|
443 |
-
not accept this License. Therefore, by modifying or propagating a
|
444 |
-
covered work, you indicate your acceptance of this License to do so.
|
445 |
-
|
446 |
-
10. Automatic Licensing of Downstream Recipients.
|
447 |
-
|
448 |
-
Each time you convey a covered work, the recipient automatically
|
449 |
-
receives a license from the original licensors, to run, modify and
|
450 |
-
propagate that work, subject to this License. You are not responsible
|
451 |
-
for enforcing compliance by third parties with this License.
|
452 |
-
|
453 |
-
An "entity transaction" is a transaction transferring control of an
|
454 |
-
organization, or substantially all assets of one, or subdividing an
|
455 |
-
organization, or merging organizations. If propagation of a covered
|
456 |
-
work results from an entity transaction, each party to that
|
457 |
-
transaction who receives a copy of the work also receives whatever
|
458 |
-
licenses to the work the party's predecessor in interest had or could
|
459 |
-
give under the previous paragraph, plus a right to possession of the
|
460 |
-
Corresponding Source of the work from the predecessor in interest, if
|
461 |
-
the predecessor has it or can get it with reasonable efforts.
|
462 |
-
|
463 |
-
You may not impose any further restrictions on the exercise of the
|
464 |
-
rights granted or affirmed under this License. For example, you may
|
465 |
-
not impose a license fee, royalty, or other charge for exercise of
|
466 |
-
rights granted under this License, and you may not initiate litigation
|
467 |
-
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
468 |
-
any patent claim is infringed by making, using, selling, offering for
|
469 |
-
sale, or importing the Program or any portion of it.
|
470 |
-
|
471 |
-
11. Patents.
|
472 |
-
|
473 |
-
A "contributor" is a copyright holder who authorizes use under this
|
474 |
-
License of the Program or a work on which the Program is based. The
|
475 |
-
work thus licensed is called the contributor's "contributor version".
|
476 |
-
|
477 |
-
A contributor's "essential patent claims" are all patent claims
|
478 |
-
owned or controlled by the contributor, whether already acquired or
|
479 |
-
hereafter acquired, that would be infringed by some manner, permitted
|
480 |
-
by this License, of making, using, or selling its contributor version,
|
481 |
-
but do not include claims that would be infringed only as a
|
482 |
-
consequence of further modification of the contributor version. For
|
483 |
-
purposes of this definition, "control" includes the right to grant
|
484 |
-
patent sublicenses in a manner consistent with the requirements of
|
485 |
-
this License.
|
486 |
-
|
487 |
-
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
488 |
-
patent license under the contributor's essential patent claims, to
|
489 |
-
make, use, sell, offer for sale, import and otherwise run, modify and
|
490 |
-
propagate the contents of its contributor version.
|
491 |
-
|
492 |
-
In the following three paragraphs, a "patent license" is any express
|
493 |
-
agreement or commitment, however denominated, not to enforce a patent
|
494 |
-
(such as an express permission to practice a patent or covenant not to
|
495 |
-
sue for patent infringement). To "grant" such a patent license to a
|
496 |
-
party means to make such an agreement or commitment not to enforce a
|
497 |
-
patent against the party.
|
498 |
-
|
499 |
-
If you convey a covered work, knowingly relying on a patent license,
|
500 |
-
and the Corresponding Source of the work is not available for anyone
|
501 |
-
to copy, free of charge and under the terms of this License, through a
|
502 |
-
publicly available network server or other readily accessible means,
|
503 |
-
then you must either (1) cause the Corresponding Source to be so
|
504 |
-
available, or (2) arrange to deprive yourself of the benefit of the
|
505 |
-
patent license for this particular work, or (3) arrange, in a manner
|
506 |
-
consistent with the requirements of this License, to extend the patent
|
507 |
-
license to downstream recipients. "Knowingly relying" means you have
|
508 |
-
actual knowledge that, but for the patent license, your conveying the
|
509 |
-
covered work in a country, or your recipient's use of the covered work
|
510 |
-
in a country, would infringe one or more identifiable patents in that
|
511 |
-
country that you have reason to believe are valid.
|
512 |
-
|
513 |
-
If, pursuant to or in connection with a single transaction or
|
514 |
-
arrangement, you convey, or propagate by procuring conveyance of, a
|
515 |
-
covered work, and grant a patent license to some of the parties
|
516 |
-
receiving the covered work authorizing them to use, propagate, modify
|
517 |
-
or convey a specific copy of the covered work, then the patent license
|
518 |
-
you grant is automatically extended to all recipients of the covered
|
519 |
-
work and works based on it.
|
520 |
-
|
521 |
-
A patent license is "discriminatory" if it does not include within
|
522 |
-
the scope of its coverage, prohibits the exercise of, or is
|
523 |
-
conditioned on the non-exercise of one or more of the rights that are
|
524 |
-
specifically granted under this License. You may not convey a covered
|
525 |
-
work if you are a party to an arrangement with a third party that is
|
526 |
-
in the business of distributing software, under which you make payment
|
527 |
-
to the third party based on the extent of your activity of conveying
|
528 |
-
the work, and under which the third party grants, to any of the
|
529 |
-
parties who would receive the covered work from you, a discriminatory
|
530 |
-
patent license (a) in connection with copies of the covered work
|
531 |
-
conveyed by you (or copies made from those copies), or (b) primarily
|
532 |
-
for and in connection with specific products or compilations that
|
533 |
-
contain the covered work, unless you entered into that arrangement,
|
534 |
-
or that patent license was granted, prior to 28 March 2007.
|
535 |
-
|
536 |
-
Nothing in this License shall be construed as excluding or limiting
|
537 |
-
any implied license or other defenses to infringement that may
|
538 |
-
otherwise be available to you under applicable patent law.
|
539 |
-
|
540 |
-
12. No Surrender of Others' Freedom.
|
541 |
-
|
542 |
-
If conditions are imposed on you (whether by court order, agreement or
|
543 |
-
otherwise) that contradict the conditions of this License, they do not
|
544 |
-
excuse you from the conditions of this License. If you cannot convey a
|
545 |
-
covered work so as to satisfy simultaneously your obligations under this
|
546 |
-
License and any other pertinent obligations, then as a consequence you may
|
547 |
-
not convey it at all. For example, if you agree to terms that obligate you
|
548 |
-
to collect a royalty for further conveying from those to whom you convey
|
549 |
-
the Program, the only way you could satisfy both those terms and this
|
550 |
-
License would be to refrain entirely from conveying the Program.
|
551 |
-
|
552 |
-
13. Use with the GNU Affero General Public License.
|
553 |
-
|
554 |
-
Notwithstanding any other provision of this License, you have
|
555 |
-
permission to link or combine any covered work with a work licensed
|
556 |
-
under version 3 of the GNU Affero General Public License into a single
|
557 |
-
combined work, and to convey the resulting work. The terms of this
|
558 |
-
License will continue to apply to the part which is the covered work,
|
559 |
-
but the special requirements of the GNU Affero General Public License,
|
560 |
-
section 13, concerning interaction through a network will apply to the
|
561 |
-
combination as such.
|
562 |
-
|
563 |
-
14. Revised Versions of this License.
|
564 |
-
|
565 |
-
The Free Software Foundation may publish revised and/or new versions of
|
566 |
-
the GNU General Public License from time to time. Such new versions will
|
567 |
-
be similar in spirit to the present version, but may differ in detail to
|
568 |
-
address new problems or concerns.
|
569 |
-
|
570 |
-
Each version is given a distinguishing version number. If the
|
571 |
-
Program specifies that a certain numbered version of the GNU General
|
572 |
-
Public License "or any later version" applies to it, you have the
|
573 |
-
option of following the terms and conditions either of that numbered
|
574 |
-
version or of any later version published by the Free Software
|
575 |
-
Foundation. If the Program does not specify a version number of the
|
576 |
-
GNU General Public License, you may choose any version ever published
|
577 |
-
by the Free Software Foundation.
|
578 |
-
|
579 |
-
If the Program specifies that a proxy can decide which future
|
580 |
-
versions of the GNU General Public License can be used, that proxy's
|
581 |
-
public statement of acceptance of a version permanently authorizes you
|
582 |
-
to choose that version for the Program.
|
583 |
-
|
584 |
-
Later license versions may give you additional or different
|
585 |
-
permissions. However, no additional obligations are imposed on any
|
586 |
-
author or copyright holder as a result of your choosing to follow a
|
587 |
-
later version.
|
588 |
-
|
589 |
-
15. Disclaimer of Warranty.
|
590 |
-
|
591 |
-
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
592 |
-
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
593 |
-
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
594 |
-
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
595 |
-
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
596 |
-
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
597 |
-
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
598 |
-
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
599 |
-
|
600 |
-
16. Limitation of Liability.
|
601 |
-
|
602 |
-
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
603 |
-
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
604 |
-
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
605 |
-
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
606 |
-
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
607 |
-
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
608 |
-
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
609 |
-
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
610 |
-
SUCH DAMAGES.
|
611 |
-
|
612 |
-
17. Interpretation of Sections 15 and 16.
|
613 |
-
|
614 |
-
If the disclaimer of warranty and limitation of liability provided
|
615 |
-
above cannot be given local legal effect according to their terms,
|
616 |
-
reviewing courts shall apply local law that most closely approximates
|
617 |
-
an absolute waiver of all civil liability in connection with the
|
618 |
-
Program, unless a warranty or assumption of liability accompanies a
|
619 |
-
copy of the Program in return for a fee.
|
620 |
-
|
621 |
-
END OF TERMS AND CONDITIONS
|
622 |
-
|
623 |
-
How to Apply These Terms to Your New Programs
|
624 |
-
|
625 |
-
If you develop a new program, and you want it to be of the greatest
|
626 |
-
possible use to the public, the best way to achieve this is to make it
|
627 |
-
free software which everyone can redistribute and change under these terms.
|
628 |
-
|
629 |
-
To do so, attach the following notices to the program. It is safest
|
630 |
-
to attach them to the start of each source file to most effectively
|
631 |
-
state the exclusion of warranty; and each file should have at least
|
632 |
-
the "copyright" line and a pointer to where the full notice is found.
|
633 |
-
|
634 |
-
<one line to give the program's name and a brief idea of what it does.>
|
635 |
-
Copyright (C) <year> <name of author>
|
636 |
-
|
637 |
-
This program is free software: you can redistribute it and/or modify
|
638 |
-
it under the terms of the GNU General Public License as published by
|
639 |
-
the Free Software Foundation, either version 3 of the License, or
|
640 |
-
(at your option) any later version.
|
641 |
-
|
642 |
-
This program is distributed in the hope that it will be useful,
|
643 |
-
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
644 |
-
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
645 |
-
GNU General Public License for more details.
|
646 |
-
|
647 |
-
You should have received a copy of the GNU General Public License
|
648 |
-
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
649 |
-
|
650 |
-
Also add information on how to contact you by electronic and paper mail.
|
651 |
-
|
652 |
-
If the program does terminal interaction, make it output a short
|
653 |
-
notice like this when it starts in an interactive mode:
|
654 |
-
|
655 |
-
<program> Copyright (C) <year> <name of author>
|
656 |
-
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
657 |
-
This is free software, and you are welcome to redistribute it
|
658 |
-
under certain conditions; type `show c' for details.
|
659 |
-
|
660 |
-
The hypothetical commands `show w' and `show c' should show the appropriate
|
661 |
-
parts of the General Public License. Of course, your program's commands
|
662 |
-
might be different; for a GUI interface, you would use an "about box".
|
663 |
-
|
664 |
-
You should also get your employer (if you work as a programmer) or school,
|
665 |
-
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
666 |
-
For more information on this, and how to apply and follow the GNU GPL, see
|
667 |
-
<http://www.gnu.org/licenses/>.
|
668 |
-
|
669 |
-
The GNU General Public License does not permit incorporating your program
|
670 |
-
into proprietary programs. If your program is a subroutine library, you
|
671 |
-
may consider it more useful to permit linking proprietary applications with
|
672 |
-
the library. If this is what you want to do, use the GNU Lesser General
|
673 |
-
Public License instead of this License. But first, please read
|
674 |
-
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
1 |
+
GNU GENERAL PUBLIC LICENSE
|
2 |
+
Version 2, June 1991
|
3 |
+
|
4 |
+
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
|
5 |
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
6 |
+
Everyone is permitted to copy and distribute verbatim copies
|
7 |
+
of this license document, but changing it is not allowed.
|
8 |
+
|
9 |
+
Preamble
|
10 |
+
|
11 |
+
The licenses for most software are designed to take away your
|
12 |
+
freedom to share and change it. By contrast, the GNU General Public
|
13 |
+
License is intended to guarantee your freedom to share and change free
|
14 |
+
software--to make sure the software is free for all its users. This
|
15 |
+
General Public License applies to most of the Free Software
|
16 |
+
Foundation's software and to any other program whose authors commit to
|
17 |
+
using it. (Some other Free Software Foundation software is covered by
|
18 |
+
the GNU Lesser General Public License instead.) You can apply it to
|
19 |
+
your programs, too.
|
20 |
+
|
21 |
+
When we speak of free software, we are referring to freedom, not
|
22 |
+
price. Our General Public Licenses are designed to make sure that you
|
23 |
+
have the freedom to distribute copies of free software (and charge for
|
24 |
+
this service if you wish), that you receive source code or can get it
|
25 |
+
if you want it, that you can change the software or use pieces of it
|
26 |
+
in new free programs; and that you know you can do these things.
|
27 |
+
|
28 |
+
To protect your rights, we need to make restrictions that forbid
|
29 |
+
anyone to deny you these rights or to ask you to surrender the rights.
|
30 |
+
These restrictions translate to certain responsibilities for you if you
|
31 |
+
distribute copies of the software, or if you modify it.
|
32 |
+
|
33 |
+
For example, if you distribute copies of such a program, whether
|
34 |
+
gratis or for a fee, you must give the recipients all the rights that
|
35 |
+
you have. You must make sure that they, too, receive or can get the
|
36 |
+
source code. And you must show them these terms so they know their
|
37 |
+
rights.
|
38 |
+
|
39 |
+
We protect your rights with two steps: (1) copyright the software, and
|
40 |
+
(2) offer you this license which gives you legal permission to copy,
|
41 |
+
distribute and/or modify the software.
|
42 |
+
|
43 |
+
Also, for each author's protection and ours, we want to make certain
|
44 |
+
that everyone understands that there is no warranty for this free
|
45 |
+
software. If the software is modified by someone else and passed on, we
|
46 |
+
want its recipients to know that what they have is not the original, so
|
47 |
+
that any problems introduced by others will not reflect on the original
|
48 |
+
authors' reputations.
|
49 |
+
|
50 |
+
Finally, any free program is threatened constantly by software
|
51 |
+
patents. We wish to avoid the danger that redistributors of a free
|
52 |
+
program will individually obtain patent licenses, in effect making the
|
53 |
+
program proprietary. To prevent this, we have made it clear that any
|
54 |
+
patent must be licensed for everyone's free use or not licensed at all.
|
55 |
+
|
56 |
+
The precise terms and conditions for copying, distribution and
|
57 |
+
modification follow.
|
58 |
+
|
59 |
+
GNU GENERAL PUBLIC LICENSE
|
60 |
+
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
61 |
+
|
62 |
+
0. This License applies to any program or other work which contains
|
63 |
+
a notice placed by the copyright holder saying it may be distributed
|
64 |
+
under the terms of this General Public License. The "Program", below,
|
65 |
+
refers to any such program or work, and a "work based on the Program"
|
66 |
+
means either the Program or any derivative work under copyright law:
|
67 |
+
that is to say, a work containing the Program or a portion of it,
|
68 |
+
either verbatim or with modifications and/or translated into another
|
69 |
+
language. (Hereinafter, translation is included without limitation in
|
70 |
+
the term "modification".) Each licensee is addressed as "you".
|
71 |
+
|
72 |
+
Activities other than copying, distribution and modification are not
|
73 |
+
covered by this License; they are outside its scope. The act of
|
74 |
+
running the Program is not restricted, and the output from the Program
|
75 |
+
is covered only if its contents constitute a work based on the
|
76 |
+
Program (independent of having been made by running the Program).
|
77 |
+
Whether that is true depends on what the Program does.
|
78 |
+
|
79 |
+
1. You may copy and distribute verbatim copies of the Program's
|
80 |
+
source code as you receive it, in any medium, provided that you
|
81 |
+
conspicuously and appropriately publish on each copy an appropriate
|
82 |
+
copyright notice and disclaimer of warranty; keep intact all the
|
83 |
+
notices that refer to this License and to the absence of any warranty;
|
84 |
+
and give any other recipients of the Program a copy of this License
|
85 |
+
along with the Program.
|
86 |
+
|
87 |
+
You may charge a fee for the physical act of transferring a copy, and
|
88 |
+
you may at your option offer warranty protection in exchange for a fee.
|
89 |
+
|
90 |
+
2. You may modify your copy or copies of the Program or any portion
|
91 |
+
of it, thus forming a work based on the Program, and copy and
|
92 |
+
distribute such modifications or work under the terms of Section 1
|
93 |
+
above, provided that you also meet all of these conditions:
|
94 |
+
|
95 |
+
a) You must cause the modified files to carry prominent notices
|
96 |
+
stating that you changed the files and the date of any change.
|
97 |
+
|
98 |
+
b) You must cause any work that you distribute or publish, that in
|
99 |
+
whole or in part contains or is derived from the Program or any
|
100 |
+
part thereof, to be licensed as a whole at no charge to all third
|
101 |
+
parties under the terms of this License.
|
102 |
+
|
103 |
+
c) If the modified program normally reads commands interactively
|
104 |
+
when run, you must cause it, when started running for such
|
105 |
+
interactive use in the most ordinary way, to print or display an
|
106 |
+
announcement including an appropriate copyright notice and a
|
107 |
+
notice that there is no warranty (or else, saying that you provide
|
108 |
+
a warranty) and that users may redistribute the program under
|
109 |
+
these conditions, and telling the user how to view a copy of this
|
110 |
+
License. (Exception: if the Program itself is interactive but
|
111 |
+
does not normally print such an announcement, your work based on
|
112 |
+
the Program is not required to print an announcement.)
|
113 |
+
|
114 |
+
These requirements apply to the modified work as a whole. If
|
115 |
+
identifiable sections of that work are not derived from the Program,
|
116 |
+
and can be reasonably considered independent and separate works in
|
117 |
+
themselves, then this License, and its terms, do not apply to those
|
118 |
+
sections when you distribute them as separate works. But when you
|
119 |
+
distribute the same sections as part of a whole which is a work based
|
120 |
+
on the Program, the distribution of the whole must be on the terms of
|
121 |
+
this License, whose permissions for other licensees extend to the
|
122 |
+
entire whole, and thus to each and every part regardless of who wrote it.
|
123 |
+
|
124 |
+
Thus, it is not the intent of this section to claim rights or contest
|
125 |
+
your rights to work written entirely by you; rather, the intent is to
|
126 |
+
exercise the right to control the distribution of derivative or
|
127 |
+
collective works based on the Program.
|
128 |
+
|
129 |
+
In addition, mere aggregation of another work not based on the Program
|
130 |
+
with the Program (or with a work based on the Program) on a volume of
|
131 |
+
a storage or distribution medium does not bring the other work under
|
132 |
+
the scope of this License.
|
133 |
+
|
134 |
+
3. You may copy and distribute the Program (or a work based on it,
|
135 |
+
under Section 2) in object code or executable form under the terms of
|
136 |
+
Sections 1 and 2 above provided that you also do one of the following:
|
137 |
+
|
138 |
+
a) Accompany it with the complete corresponding machine-readable
|
139 |
+
source code, which must be distributed under the terms of Sections
|
140 |
+
1 and 2 above on a medium customarily used for software interchange; or,
|
141 |
+
|
142 |
+
b) Accompany it with a written offer, valid for at least three
|
143 |
+
years, to give any third party, for a charge no more than your
|
144 |
+
cost of physically performing source distribution, a complete
|
145 |
+
machine-readable copy of the corresponding source code, to be
|
146 |
+
distributed under the terms of Sections 1 and 2 above on a medium
|
147 |
+
customarily used for software interchange; or,
|
148 |
+
|
149 |
+
c) Accompany it with the information you received as to the offer
|
150 |
+
to distribute corresponding source code. (This alternative is
|
151 |
+
allowed only for noncommercial distribution and only if you
|
152 |
+
received the program in object code or executable form with such
|
153 |
+
an offer, in accord with Subsection b above.)
|
154 |
+
|
155 |
+
The source code for a work means the preferred form of the work for
|
156 |
+
making modifications to it. For an executable work, complete source
|
157 |
+
code means all the source code for all modules it contains, plus any
|
158 |
+
associated interface definition files, plus the scripts used to
|
159 |
+
control compilation and installation of the executable. However, as a
|
160 |
+
special exception, the source code distributed need not include
|
161 |
+
anything that is normally distributed (in either source or binary
|
162 |
+
form) with the major components (compiler, kernel, and so on) of the
|
163 |
+
operating system on which the executable runs, unless that component
|
164 |
+
itself accompanies the executable.
|
165 |
+
|
166 |
+
If distribution of executable or object code is made by offering
|
167 |
+
access to copy from a designated place, then offering equivalent
|
168 |
+
access to copy the source code from the same place counts as
|
169 |
+
distribution of the source code, even though third parties are not
|
170 |
+
compelled to copy the source along with the object code.
|
171 |
+
|
172 |
+
4. You may not copy, modify, sublicense, or distribute the Program
|
173 |
+
except as expressly provided under this License. Any attempt
|
174 |
+
otherwise to copy, modify, sublicense or distribute the Program is
|
175 |
+
void, and will automatically terminate your rights under this License.
|
176 |
+
However, parties who have received copies, or rights, from you under
|
177 |
+
this License will not have their licenses terminated so long as such
|
178 |
+
parties remain in full compliance.
|
179 |
+
|
180 |
+
5. You are not required to accept this License, since you have not
|
181 |
+
signed it. However, nothing else grants you permission to modify or
|
182 |
+
distribute the Program or its derivative works. These actions are
|
183 |
+
prohibited by law if you do not accept this License. Therefore, by
|
184 |
+
modifying or distributing the Program (or any work based on the
|
185 |
+
Program), you indicate your acceptance of this License to do so, and
|
186 |
+
all its terms and conditions for copying, distributing or modifying
|
187 |
+
the Program or works based on it.
|
188 |
+
|
189 |
+
6. Each time you redistribute the Program (or any work based on the
|
190 |
+
Program), the recipient automatically receives a license from the
|
191 |
+
original licensor to copy, distribute or modify the Program subject to
|
192 |
+
these terms and conditions. You may not impose any further
|
193 |
+
restrictions on the recipients' exercise of the rights granted herein.
|
194 |
+
You are not responsible for enforcing compliance by third parties to
|
195 |
+
this License.
|
196 |
+
|
197 |
+
7. If, as a consequence of a court judgment or allegation of patent
|
198 |
+
infringement or for any other reason (not limited to patent issues),
|
199 |
+
conditions are imposed on you (whether by court order, agreement or
|
200 |
+
otherwise) that contradict the conditions of this License, they do not
|
201 |
+
excuse you from the conditions of this License. If you cannot
|
202 |
+
distribute so as to satisfy simultaneously your obligations under this
|
203 |
+
License and any other pertinent obligations, then as a consequence you
|
204 |
+
may not distribute the Program at all. For example, if a patent
|
205 |
+
license would not permit royalty-free redistribution of the Program by
|
206 |
+
all those who receive copies directly or indirectly through you, then
|
207 |
+
the only way you could satisfy both it and this License would be to
|
208 |
+
refrain entirely from distribution of the Program.
|
209 |
+
|
210 |
+
If any portion of this section is held invalid or unenforceable under
|
211 |
+
any particular circumstance, the balance of the section is intended to
|
212 |
+
apply and the section as a whole is intended to apply in other
|
213 |
+
circumstances.
|
214 |
+
|
215 |
+
It is not the purpose of this section to induce you to infringe any
|
216 |
+
patents or other property right claims or to contest validity of any
|
217 |
+
such claims; this section has the sole purpose of protecting the
|
218 |
+
integrity of the free software distribution system, which is
|
219 |
+
implemented by public license practices. Many people have made
|
220 |
+
generous contributions to the wide range of software distributed
|
221 |
+
through that system in reliance on consistent application of that
|
222 |
+
system; it is up to the author/donor to decide if he or she is willing
|
223 |
+
to distribute software through any other system and a licensee cannot
|
224 |
+
impose that choice.
|
225 |
+
|
226 |
+
This section is intended to make thoroughly clear what is believed to
|
227 |
+
be a consequence of the rest of this License.
|
228 |
+
|
229 |
+
8. If the distribution and/or use of the Program is restricted in
|
230 |
+
certain countries either by patents or by copyrighted interfaces, the
|
231 |
+
original copyright holder who places the Program under this License
|
232 |
+
may add an explicit geographical distribution limitation excluding
|
233 |
+
those countries, so that distribution is permitted only in or among
|
234 |
+
countries not thus excluded. In such case, this License incorporates
|
235 |
+
the limitation as if written in the body of this License.
|
236 |
+
|
237 |
+
9. The Free Software Foundation may publish revised and/or new versions
|
238 |
+
of the General Public License from time to time. Such new versions will
|
239 |
+
be similar in spirit to the present version, but may differ in detail to
|
240 |
+
address new problems or concerns.
|
241 |
+
|
242 |
+
Each version is given a distinguishing version number. If the Program
|
243 |
+
specifies a version number of this License which applies to it and "any
|
244 |
+
later version", you have the option of following the terms and conditions
|
245 |
+
either of that version or of any later version published by the Free
|
246 |
+
Software Foundation. If the Program does not specify a version number of
|
247 |
+
this License, you may choose any version ever published by the Free Software
|
248 |
+
Foundation.
|
249 |
+
|
250 |
+
10. If you wish to incorporate parts of the Program into other free
|
251 |
+
programs whose distribution conditions are different, write to the author
|
252 |
+
to ask for permission. For software which is copyrighted by the Free
|
253 |
+
Software Foundation, write to the Free Software Foundation; we sometimes
|
254 |
+
make exceptions for this. Our decision will be guided by the two goals
|
255 |
+
of preserving the free status of all derivatives of our free software and
|
256 |
+
of promoting the sharing and reuse of software generally.
|
257 |
+
|
258 |
+
NO WARRANTY
|
259 |
+
|
260 |
+
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
261 |
+
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
262 |
+
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
263 |
+
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
264 |
+
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
265 |
+
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
266 |
+
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
267 |
+
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
268 |
+
REPAIR OR CORRECTION.
|
269 |
+
|
270 |
+
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
271 |
+
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
272 |
+
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
273 |
+
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
274 |
+
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
275 |
+
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
276 |
+
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
277 |
+
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
278 |
+
POSSIBILITY OF SUCH DAMAGES.
|
279 |
+
|
280 |
+
END OF TERMS AND CONDITIONS
|
281 |
+
|
282 |
+
How to Apply These Terms to Your New Programs
|
283 |
+
|
284 |
+
If you develop a new program, and you want it to be of the greatest
|
285 |
+
possible use to the public, the best way to achieve this is to make it
|
286 |
+
free software which everyone can redistribute and change under these terms.
|
287 |
+
|
288 |
+
To do so, attach the following notices to the program. It is safest
|
289 |
+
to attach them to the start of each source file to most effectively
|
290 |
+
convey the exclusion of warranty; and each file should have at least
|
291 |
+
the "copyright" line and a pointer to where the full notice is found.
|
292 |
+
|
293 |
+
<one line to give the program's name and a brief idea of what it does.>
|
294 |
+
Copyright (C) <year> <name of author>
|
295 |
+
|
296 |
+
This program is free software; you can redistribute it and/or modify
|
297 |
+
it under the terms of the GNU General Public License as published by
|
298 |
+
the Free Software Foundation; either version 2 of the License, or
|
299 |
+
(at your option) any later version.
|
300 |
+
|
301 |
+
This program is distributed in the hope that it will be useful,
|
302 |
+
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
303 |
+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
304 |
+
GNU General Public License for more details.
|
305 |
+
|
306 |
+
You should have received a copy of the GNU General Public License along
|
307 |
+
with this program; if not, write to the Free Software Foundation, Inc.,
|
308 |
+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
309 |
+
|
310 |
+
Also add information on how to contact you by electronic and paper mail.
|
311 |
+
|
312 |
+
If the program is interactive, make it output a short notice like this
|
313 |
+
when it starts in an interactive mode:
|
314 |
+
|
315 |
+
Gnomovision version 69, Copyright (C) year name of author
|
316 |
+
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
317 |
+
This is free software, and you are welcome to redistribute it
|
318 |
+
under certain conditions; type `show c' for details.
|
319 |
+
|
320 |
+
The hypothetical commands `show w' and `show c' should show the appropriate
|
321 |
+
parts of the General Public License. Of course, the commands you use may
|
322 |
+
be called something other than `show w' and `show c'; they could even be
|
323 |
+
mouse-clicks or menu items--whatever suits your program.
|
324 |
+
|
325 |
+
You should also get your employer (if you work as a programmer) or your
|
326 |
+
school, if any, to sign a "copyright disclaimer" for the program, if
|
327 |
+
necessary. Here is a sample; alter the names:
|
328 |
+
|
329 |
+
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
330 |
+
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
331 |
+
|
332 |
+
<signature of Ty Coon>, 1 April 1989
|
333 |
+
Ty Coon, President of Vice
|
334 |
+
|
335 |
+
This General Public License does not permit incorporating your program into
|
336 |
+
proprietary programs. If your program is a subroutine library, you may
|
337 |
+
consider it more useful to permit linking proprietary applications with the
|
338 |
+
library. If this is what you want to do, use the GNU Lesser General
|
339 |
+
Public License instead of this License.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
inc/Database/Exporter.php
CHANGED
@@ -1,713 +1,713 @@
|
|
1 |
-
<?php /** @noinspection SqlNoDataSourceInspection */
|
2 |
-
|
3 |
-
namespace Inpsyde\SearchReplace\Database;
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Class Exporter
|
7 |
-
*
|
8 |
-
* @property bool|resource fb
|
9 |
-
* @package Inpsyde\SearchReplace\Database
|
10 |
-
*/
|
11 |
-
class Exporter {
|
12 |
-
|
13 |
-
/**
|
14 |
-
* Stores all error messages in a WP_Error Object
|
15 |
-
*/
|
16 |
-
private $errors;
|
17 |
-
|
18 |
-
/**
|
19 |
-
* @string The Path to the Backup Directory
|
20 |
-
*/
|
21 |
-
private $backup_dir;
|
22 |
-
|
23 |
-
/**
|
24 |
-
* @var Replace
|
25 |
-
*/
|
26 |
-
private $replace;
|
27 |
-
|
28 |
-
/**
|
29 |
-
* @var Manager
|
30 |
-
*/
|
31 |
-
private $dbm;
|
32 |
-
|
33 |
-
/**
|
34 |
-
* Count of rows to be replaced at a time
|
35 |
-
*
|
36 |
-
* @var int
|
37 |
-
*/
|
38 |
-
private $page_size = 100;
|
39 |
-
|
40 |
-
/**
|
41 |
-
* Stores the filename of the backup file
|
42 |
-
*/
|
43 |
-
private $backup_filename;
|
44 |
-
|
45 |
-
/**
|
46 |
-
* Store file path.
|
47 |
-
*
|
48 |
-
* @var $fp
|
49 |
-
*/
|
50 |
-
private $fp;
|
51 |
-
|
52 |
-
/**
|
53 |
-
* Store csv data
|
54 |
-
*
|
55 |
-
* @var array
|
56 |
-
*/
|
57 |
-
private $csv_data = [];
|
58 |
-
|
59 |
-
/**
|
60 |
-
* Exporter constructor.
|
61 |
-
*
|
62 |
-
* @param Replace $replace
|
63 |
-
* @param Manager $dbm
|
64 |
-
* @param \WP_Error $wp_error
|
65 |
-
*/
|
66 |
-
public function __construct( Replace $replace, Manager $dbm, \WP_Error $wp_error ) {
|
67 |
-
|
68 |
-
$this->errors = $wp_error;
|
69 |
-
$this->backup_dir = get_temp_dir();
|
70 |
-
$this->replace = $replace;
|
71 |
-
$this->dbm = $dbm;
|
72 |
-
}
|
73 |
-
|
74 |
-
/**
|
75 |
-
* Write to the backup file
|
76 |
-
*
|
77 |
-
* @param string $search
|
78 |
-
* @param string $replace
|
79 |
-
* @param array $tables The array of table names that should be exported.
|
80 |
-
* @param bool $domain_replace If set, exporter will change the domain name without leading http:// in table
|
81 |
-
* wp_blogs if we are on a multisite
|
82 |
-
* @param string $new_table_prefix
|
83 |
-
* @param null $csv
|
84 |
-
*
|
85 |
-
* @return array $report $report [ 'filename'] : Name of Backup file,
|
86 |
-
* $report[ 'errors'] : WP_Error_object,
|
87 |
-
* $report ['changes'] : Array with replacements in tables
|
88 |
-
* @throws \Throwable
|
89 |
-
*/
|
90 |
-
public function db_backup(
|
91 |
-
$search = '',
|
92 |
-
$replace = '',
|
93 |
-
$tables = [],
|
94 |
-
$domain_replace = false,
|
95 |
-
$new_table_prefix = '',
|
96 |
-
$csv = null
|
97 |
-
) {
|
98 |
-
|
99 |
-
if ( count( $tables ) < 1 ) {
|
100 |
-
$tables = $this->dbm->get_tables();
|
101 |
-
}
|
102 |
-
|
103 |
-
$report = [
|
104 |
-
'errors' => null,
|
105 |
-
'changes' => [],
|
106 |
-
'tables' => '0',
|
107 |
-
'changes_count' => '0',
|
108 |
-
'filename' => '',
|
109 |
-
];
|
110 |
-
|
111 |
-
$table_prefix = $this->dbm->get_base_prefix();
|
112 |
-
|
113 |
-
// wp_blogs needs special treatment in multisite domain replace, we need to check later if we are working on it.
|
114 |
-
$wp_blogs_table = $table_prefix . 'blogs';
|
115 |
-
|
116 |
-
$this->backup_filename = $new_table_prefix === '' ?
|
117 |
-
DB_NAME . "_$table_prefix.sql" :
|
118 |
-
DB_NAME . "_$new_table_prefix.sql";
|
119 |
-
|
120 |
-
// If the directory for the backup isn't writable, don't proceed.
|
121 |
-
// @ToDo Use WP_Filesystem() to access to the file system.
|
122 |
-
if ( ! is_writable( $this->backup_dir ) ) {
|
123 |
-
$this->errors->add( 9, esc_attr__( 'The backup directory is not writable!', 'search-and-replace' ) );
|
124 |
-
|
125 |
-
return $report;
|
126 |
-
}
|
127 |
-
|
128 |
-
$this->fp = $this->open( $this->backup_dir . $this->backup_filename );
|
129 |
-
|
130 |
-
if ( ! $this->fp ) {
|
131 |
-
$this->errors->add(
|
132 |
-
8,
|
133 |
-
esc_attr__( 'Could not open the backup file for writing!', 'search-and-replace' )
|
134 |
-
);
|
135 |
-
|
136 |
-
return $report;
|
137 |
-
}
|
138 |
-
|
139 |
-
// Begin new backup of MySql get charset. if not set assume utf8.
|
140 |
-
$charset = ( defined( 'DB_CHARSET' ) ? DB_CHARSET : 'utf8mb4' );
|
141 |
-
|
142 |
-
$this->stow( '# ' . esc_attr__( 'WordPress MySQL database backup', 'search-and-replace' ) . "\n" );
|
143 |
-
$this->stow( "#\n" );
|
144 |
-
$this->stow( '# ' . sprintf( __( 'Generated: %s', 'search-and-replace' ), date( 'l j. F Y H:i T' ) ) . "\n" );
|
145 |
-
$this->stow( '# ' . sprintf( __( 'Hostname: %s', 'search-and-replace' ), DB_HOST ) . "\n" );
|
146 |
-
$this->stow( '# ' . sprintf( __( 'Database: %s', 'search-and-replace' ), $this->backquote( DB_NAME ) ) . "\n" );
|
147 |
-
|
148 |
-
if ( '' !== $new_table_prefix ) {
|
149 |
-
$this->stow(
|
150 |
-
'# ' . sprintf(
|
151 |
-
/* translators: $1 and $2 are the name of the database. */
|
152 |
-
__( 'Changed table prefix: From %1$s to %2$s ', 'search-and-replace' ),
|
153 |
-
$table_prefix,
|
154 |
-
$new_table_prefix
|
155 |
-
)
|
156 |
-
. "\n"
|
157 |
-
);
|
158 |
-
}
|
159 |
-
|
160 |
-
$this->stow( "# --------------------------------------------------------\n" );
|
161 |
-
$this->stow( "/*!40101 SET NAMES $charset */;\n" );
|
162 |
-
$this->stow( "# --------------------------------------------------------\n" );
|
163 |
-
|
164 |
-
foreach ( $tables as $table ) {
|
165 |
-
|
166 |
-
// Count tables.
|
167 |
-
$report ['tables'] ++;
|
168 |
-
|
169 |
-
/**
|
170 |
-
* Check if we are replacing the domain in a multisite.
|
171 |
-
* If so, we replace in wp_blogs the stripped url without http(s), because the domains
|
172 |
-
* are stored without http://
|
173 |
-
*/
|
174 |
-
if ( $table === $wp_blogs_table && $domain_replace && is_multisite() ) {
|
175 |
-
$stripped_url_search = substr( $search, strpos( $search, '/' ) + 2 );
|
176 |
-
$stripped_url_replace = substr( $replace, strpos( $replace, '/' ) + 2 );
|
177 |
-
|
178 |
-
// Backup table.
|
179 |
-
$table_report = $this->backup_table(
|
180 |
-
$stripped_url_search,
|
181 |
-
$stripped_url_replace,
|
182 |
-
$table,
|
183 |
-
$new_table_prefix
|
184 |
-
);
|
185 |
-
} else {
|
186 |
-
// Backup table.
|
187 |
-
$table_report = $this->backup_table( $search, $replace, $table, $new_table_prefix, $csv );
|
188 |
-
}
|
189 |
-
|
190 |
-
// Log changes if any.
|
191 |
-
if ( 0 !== $table_report['change'] ) {
|
192 |
-
$report['changes'][ $table ] = $table_report;
|
193 |
-
|
194 |
-
$report ['changes_count'] += $table_report['change'];
|
195 |
-
}
|
196 |
-
}
|
197 |
-
|
198 |
-
$this->close( $this->fp );
|
199 |
-
|
200 |
-
// Return errors if any.
|
201 |
-
if ( count( $this->errors->get_error_codes() ) ) {
|
202 |
-
$report['errors'] = $this->errors;
|
203 |
-
}
|
204 |
-
|
205 |
-
$report ['filename'] = $this->backup_filename;
|
206 |
-
|
207 |
-
return $report;
|
208 |
-
}
|
209 |
-
|
210 |
-
/**
|
211 |
-
* Open Resource
|
212 |
-
*
|
213 |
-
* @param string $filename
|
214 |
-
* @param string $mode
|
215 |
-
*
|
216 |
-
* @return bool|resource
|
217 |
-
*/
|
218 |
-
private function open( $filename = '', $mode = 'wb' ) {
|
219 |
-
|
220 |
-
if ( '' === $filename ) {
|
221 |
-
return false;
|
222 |
-
}
|
223 |
-
|
224 |
-
return @fopen( $filename, $mode );
|
225 |
-
}
|
226 |
-
|
227 |
-
/**
|
228 |
-
* writes a line to the backup file
|
229 |
-
*
|
230 |
-
* @param $query_line
|
231 |
-
*/
|
232 |
-
private function stow( $query_line ) {
|
233 |
-
|
234 |
-
if ( @fwrite( $this->fp, $query_line ) === false ) {
|
235 |
-
$this->errors->add(
|
236 |
-
4,
|
237 |
-
sprintf(
|
238 |
-
esc_attr__(
|
239 |
-
'There was an error writing a line to the backup script: %s',
|
240 |
-
'search-and-replace'
|
241 |
-
),
|
242 |
-
(int) $query_line
|
243 |
-
)
|
244 |
-
);
|
245 |
-
}
|
246 |
-
}
|
247 |
-
|
248 |
-
/**
|
249 |
-
* Back Quote
|
250 |
-
*
|
251 |
-
* Add backquotes to tables and db-names in
|
252 |
-
* SQL queries. Taken from phpMyAdmin.
|
253 |
-
*
|
254 |
-
* @param $a_name
|
255 |
-
*
|
256 |
-
* @return array|string
|
257 |
-
*/
|
258 |
-
private function backquote( $a_name ) {
|
259 |
-
|
260 |
-
if ( ! empty( $a_name ) && $a_name !== '*' ) {
|
261 |
-
if ( is_array( $a_name ) ) {
|
262 |
-
$result = [];
|
263 |
-
reset( $a_name );
|
264 |
-
foreach ( $a_name as $key => $val ) {
|
265 |
-
// while ( list( $key, $val ) = each( $a_name ) ) {
|
266 |
-
$result[ $key ] = '`' . $val . '`';
|
267 |
-
}
|
268 |
-
|
269 |
-
return $result;
|
270 |
-
}
|
271 |
-
|
272 |
-
return '`' . $a_name . '`';
|
273 |
-
}
|
274 |
-
|
275 |
-
return $a_name;
|
276 |
-
}
|
277 |
-
|
278 |
-
/**
|
279 |
-
* Backup Table
|
280 |
-
*
|
281 |
-
* Taken partially from phpMyAdmin and partially from
|
282 |
-
* Alain Wolf, Zurich - Switzerland
|
283 |
-
*
|
284 |
-
* Website: http://restkultur.ch/personal/wolf/scripts/db_backup/
|
285 |
-
* Modified by Scott Merrill (http://www.skippy.net/) to use the WordPress $wpdb object
|
286 |
-
*
|
287 |
-
* @param string $search
|
288 |
-
* @param string $replace
|
289 |
-
* @param string $table
|
290 |
-
* @param string $new_table_prefix
|
291 |
-
*
|
292 |
-
* @return array $table_report Reports the changes made to the db.
|
293 |
-
* @throws \Throwable
|
294 |
-
*/
|
295 |
-
public function backup_table( $search = '', $replace = '', $table, $new_table_prefix = '', $csv = null ) {
|
296 |
-
|
297 |
-
$table_report = [
|
298 |
-
'table_name' => $table,
|
299 |
-
'rows' => 0,
|
300 |
-
'change' => 0,
|
301 |
-
'changes' => [],
|
302 |
-
];
|
303 |
-
|
304 |
-
// Default columns values.
|
305 |
-
$defs = [];
|
306 |
-
// Integer value container.
|
307 |
-
$ints = [];
|
308 |
-
|
309 |
-
// This array is storage for maybe_serialized values. We must prevent deserialization of user supplied content.
|
310 |
-
$maybe_serialized = [];
|
311 |
-
$binaries = [];
|
312 |
-
|
313 |
-
// Do we need to replace the prefix?
|
314 |
-
$table_prefix = $this->dbm->get_base_prefix();
|
315 |
-
$new_table = $table;
|
316 |
-
|
317 |
-
if ( '' !== $new_table_prefix ) {
|
318 |
-
$new_table = $this->get_new_table_name( $table, $new_table_prefix );
|
319 |
-
}
|
320 |
-
|
321 |
-
// Create the SQL statements
|
322 |
-
$this->stow( '# --------------------------------------------------------' . "\n" );
|
323 |
-
$this->stow( '# ' . sprintf( __( 'Table: %s', 'search-and-replace' ), $this->backquote( $new_table ) ) . "\n" );
|
324 |
-
|
325 |
-
// Retrieve table structure.
|
326 |
-
$table_structure = $this->dbm->get_table_structure( $table );
|
327 |
-
|
328 |
-
if ( ! $table_structure ) {
|
329 |
-
$this->errors->add( 1, __( 'Error getting table details', 'search-and-replace' ) . ": $table" );
|
330 |
-
|
331 |
-
return $table_report;
|
332 |
-
}
|
333 |
-
|
334 |
-
$this->stow( "\n\n" );
|
335 |
-
$this->stow( "#\n" );
|
336 |
-
$this->stow(
|
337 |
-
'# ' . sprintf(
|
338 |
-
__( 'Delete any existing table %s', 'search-and-replace' ),
|
339 |
-
$this->backquote( $new_table )
|
340 |
-
) . "\n"
|
341 |
-
);
|
342 |
-
$this->stow( "#\n" );
|
343 |
-
$this->stow( "\n" );
|
344 |
-
$this->stow( 'DROP TABLE IF EXISTS ' . $this->backquote( $new_table ) . ';' . "\n" );
|
345 |
-
|
346 |
-
// Table structure
|
347 |
-
// Comment in SQL-file
|
348 |
-
$this->stow( "\n\n" );
|
349 |
-
$this->stow( "#\n" );
|
350 |
-
$this->stow(
|
351 |
-
'# ' . sprintf(
|
352 |
-
__( 'Table structure of table %s', 'search-and-replace' ),
|
353 |
-
$this->backquote( $new_table )
|
354 |
-
) . "\n"
|
355 |
-
);
|
356 |
-
$this->stow( "#\n" );
|
357 |
-
$this->stow( "\n" );
|
358 |
-
|
359 |
-
/** @var array $create_table */
|
360 |
-
$create_table = $this->dbm->get_create_table_statement( $table );
|
361 |
-
|
362 |
-
if ( false === $create_table ) {
|
363 |
-
/* translators: $1 is the name of the table */
|
364 |
-
$err_msg = sprintf( __( 'Error with SHOW CREATE TABLE for %s.', 'search-and-replace' ), $table );
|
365 |
-
$this->errors->add( 2, $err_msg );
|
366 |
-
$this->stow( "#\n# $err_msg\n#\n" );
|
367 |
-
}
|
368 |
-
|
369 |
-
// Replace prefix if necessary
|
370 |
-
if ( '' !== $new_table_prefix ) {
|
371 |
-
$create_table[0][1] = str_replace( $table, $new_table, $create_table[0][1] );
|
372 |
-
$table_report['new_table_name'] = $new_table;
|
373 |
-
}
|
374 |
-
|
375 |
-
$this->stow( $create_table[0][1] . ' ;' );
|
376 |
-
|
377 |
-
if ( false === $table_structure ) {
|
378 |
-
/* translators: $1 is the name of the table */
|
379 |
-
$err_msg = sprintf( __( 'Error getting table structure of %s', 'search-and-replace' ), $table );
|
380 |
-
$this->errors->add( 3, $err_msg );
|
381 |
-
$this->stow( "#\n# $err_msg\n#\n" );
|
382 |
-
}
|
383 |
-
|
384 |
-
// Comment in SQL-file
|
385 |
-
$this->stow( "\n\n" );
|
386 |
-
$this->stow( "#\n" );
|
387 |
-
$this->stow(
|
388 |
-
/* translators: $1 is the name of the new table */
|
389 |
-
'# ' . sprintf( __( 'Data contents of table %s', 'search-and-replace' ), $this->backquote( $new_table ) ) .
|
390 |
-
"\n"
|
391 |
-
);
|
392 |
-
$this->stow( "#\n" );
|
393 |
-
|
394 |
-
foreach ( $table_structure as $struct ) {
|
395 |
-
if ( 0 === strpos( $struct->Type, 'tinyint' )
|
396 |
-
|| 0 === stripos( $struct->Type, 'smallint' )
|
397 |
-
|| 0 === stripos( $struct->Type, 'mediumint' )
|
398 |
-
|| 0 === stripos( $struct->Type, 'int' )
|
399 |
-
|| 0 === stripos( $struct->Type, 'bigint' )
|
400 |
-
) {
|
401 |
-
$defs[ strtolower( $struct->Field ) ] = ( null === $struct->Default ) ? 'NULL' : $struct->Default;
|
402 |
-
$ints[ strtolower( $struct->Field ) ] = '1';
|
403 |
-
|
404 |
-
} elseif ( 0 === stripos( $struct->Type, 'binary' )
|
405 |
-
|| 0 === stripos( $struct->Type, 'varbinary' )
|
406 |
-
|| 0 === stripos( $struct->Type, 'blob' )
|
407 |
-
|| 0 === stripos( $struct->Type, 'tinyblob' )
|
408 |
-
|| 0 === stripos( $struct->Type, 'mediumblob' )
|
409 |
-
|| 0 === stripos( $struct->Type, 'longblob' )
|
410 |
-
) {
|
411 |
-
$binaries[ strtolower( $struct->Field ) ] = 1;
|
412 |
-
}
|
413 |
-
|
414 |
-
// Longtext is used for meta_values as best practice in all of the automatic products.
|
415 |
-
if ( 0 === stripos( $struct->Type, 'longtext' ) ) {
|
416 |
-
$maybe_serialized[] = strtolower( $struct->Field );
|
417 |
-
}
|
418 |
-
}
|
419 |
-
|
420 |
-
// Split columns array in primary key string and columns array.
|
421 |
-
$columns = $this->dbm->get_columns( $table );
|
422 |
-
$primary_key = $columns[0];
|
423 |
-
$row_count = $this->dbm->get_rows( $table );
|
424 |
-
$page_size = $this->page_size;
|
425 |
-
$pages = ceil( $row_count / $page_size );
|
426 |
-
|
427 |
-
// Prepare CSV data.
|
428 |
-
if ( $csv !== null ) {
|
429 |
-
$csv_lines = explode( "\n", $csv );
|
430 |
-
$csv_head = str_getcsv( 'search,replace' );
|
431 |
-
|
432 |
-
foreach ( $csv_lines as $line ) {
|
433 |
-
$this->csv_data[] = array_combine( $csv_head, str_getcsv( $line ) );
|
434 |
-
}
|
435 |
-
}
|
436 |
-
|
437 |
-
for ( $page = 0; $page < $pages; $page ++ ) {
|
438 |
-
$start = $page * $page_size;
|
439 |
-
|
440 |
-
$table_data = $this->dbm->get_table_content( $table, $start, $page_size );
|
441 |
-
|
442 |
-
$entries = 'INSERT INTO ' . $this->backquote( $new_table ) . ' VALUES (';
|
443 |
-
// \x08\\x09, not required
|
444 |
-
$hex_search = [ "\x00", "\x0a", "\x0d", "\x1a" ];
|
445 |
-
$hex_replace = [ '\0', '\n', '\r', '\Z' ];
|
446 |
-
|
447 |
-
if ( $table_data ) :
|
448 |
-
foreach ( $table_data as $row ) :
|
449 |
-
$values = [];
|
450 |
-
$table_report['rows'] ++;
|
451 |
-
|
452 |
-
foreach ( $row as $column => $value ) :
|
453 |
-
// If "change database prefix" is set we have to look for occurrences of the old prefix
|
454 |
-
// in the db entries and change them.
|
455 |
-
if ( $new_table !== $table ) {
|
456 |
-
// Check if column is expected to hold serialized value.
|
457 |
-
if ( is_serialized( $value, false )
|
458 |
-
&& in_array( strtolower( $column ), $maybe_serialized, true )
|
459 |
-
) {
|
460 |
-
$value = $this->replace->recursive_unserialize_replace(
|
461 |
-
$table_prefix,
|
462 |
-
$new_table_prefix,
|
463 |
-
$value
|
464 |
-
);
|
465 |
-
} else {
|
466 |
-
$value = str_replace( $table_prefix, $new_table_prefix, $value );
|
467 |
-
}
|
468 |
-
}
|
469 |
-
|
470 |
-
// Skip replace if no search pattern
|
471 |
-
// Check if we need to replace something
|
472 |
-
// Skip primary_key
|
473 |
-
// Skip `guid` column https://codex.wordpress.org/Changing_The_Site_URL#Important_GUID_Note
|
474 |
-
if ( $column !== $primary_key && $column !== 'guid' ) {
|
475 |
-
// Initialize
|
476 |
-
$edited_data = '';
|
477 |
-
|
478 |
-
if ( '' !== $search ) {
|
479 |
-
// Check if column is expected to hold serialized value.
|
480 |
-
if ( is_serialized( $value, false )
|
481 |
-
&& in_array( strtolower( $column ), $maybe_serialized, true )
|
482 |
-
) {
|
483 |
-
$edited_data = $this->replace->recursive_unserialize_replace(
|
484 |
-
$search,
|
485 |
-
$replace,
|
486 |
-
$value
|
487 |
-
);
|
488 |
-
} else {
|
489 |
-
$edited_data = str_replace( $search, $replace, $value );
|
490 |
-
}
|
491 |
-
}
|
492 |
-
|
493 |
-
// If csv string has passed let's replace those values.
|
494 |
-
if ( $csv !== null ) {
|
495 |
-
foreach ( $this->csv_data as $entry ) {
|
496 |
-
$edited_data = is_serialized( $edited_data, false ) ?
|
497 |
-
$this->replace->recursive_unserialize_replace(
|
498 |
-
$entry['search'],
|
499 |
-
$entry['replace'],
|
500 |
-
$edited_data
|
501 |
-
) : str_replace( $entry['search'], $entry['replace'], $value );
|
502 |
-
}
|
503 |
-
}
|
504 |
-
|
505 |
-
// When a replace happen, update the table report.
|
506 |
-
if ( $edited_data && $edited_data !== $value ) {
|
507 |
-
$table_report['change'] ++;
|
508 |
-
|
509 |
-
// log changes
|
510 |
-
$table_report['changes'][] = [
|
511 |
-
'row' => $table_report['rows'],
|
512 |
-
'column' => $column,
|
513 |
-
'from' => $value,
|
514 |
-
'to' => $edited_data,
|
515 |
-
];
|
516 |
-
|
517 |
-
$value = $edited_data;
|
518 |
-
}
|
519 |
-
}
|
520 |
-
|
521 |
-
if ( isset( $ints[ strtolower( $column ) ] ) ) {
|
522 |
-
// make sure there are no blank spots in the insert syntax,
|
523 |
-
// yet try to avoid quotation marks around integers
|
524 |
-
$value = ( null === $value || '' === $value ) ? $defs[ strtolower( $column ) ] : $value;
|
525 |
-
$values[] = ( '' === $value ) ? "''" : $value;
|
526 |
-
} else if ( isset( $binaries[ strtolower( $column ) ] ) ) {
|
527 |
-
$hex = unpack( 'H*', $value );
|
528 |
-
$values[] = "0x$hex[1]";
|
529 |
-
} else {
|
530 |
-
$values[] = "'" . str_replace(
|
531 |
-
$hex_search,
|
532 |
-
$hex_replace,
|
533 |
-
$this->sql_addslashes( $value )
|
534 |
-
) . "'";
|
535 |
-
}
|
536 |
-
endforeach;
|
537 |
-
|
538 |
-
$this->stow( " \n" . $entries . implode( ', ', $values ) . ');' );
|
539 |
-
|
540 |
-
endforeach;
|
541 |
-
endif;
|
542 |
-
}
|
543 |
-
|
544 |
-
// Create footer/closing comment in SQL-file
|
545 |
-
$this->stow( "\n" );
|
546 |
-
$this->stow( "#\n" );
|
547 |
-
$this->stow(
|
548 |
-
'# ' . sprintf(
|
549 |
-
/* translators: $1 is the name of the table */
|
550 |
-
__( 'End of data contents of table %s', 'search-and-replace' ),
|
551 |
-
$this->backquote( $new_table )
|
552 |
-
) . "\n"
|
553 |
-
);
|
554 |
-
$this->stow( "# --------------------------------------------------------\n" );
|
555 |
-
$this->stow( "\n" );
|
556 |
-
|
557 |
-
return $table_report;
|
558 |
-
}
|
559 |
-
|
560 |
-
/**
|
561 |
-
* Get new Table name
|
562 |
-
*
|
563 |
-
* strips the current table prefix and adds a new one provided in $new_table_prefix
|
564 |
-
*
|
565 |
-
* @param $table
|
566 |
-
* @param $new_table_prefix
|
567 |
-
*
|
568 |
-
* @return string The table name with new prefix
|
569 |
-
*/
|
570 |
-
private function get_new_table_name( $table, $new_table_prefix ) {
|
571 |
-
|
572 |
-
// Get length of base_prefix
|
573 |
-
$prefix = $this->dbm->get_base_prefix();
|
574 |
-
$prefix_length = strlen( $prefix );
|
575 |
-
// Strip old prefix
|
576 |
-
$part_after_prefix = substr( $table, $prefix_length );
|
577 |
-
|
578 |
-
// Build new table name
|
579 |
-
return $new_table_prefix . $part_after_prefix;
|
580 |
-
}
|
581 |
-
|
582 |
-
/**
|
583 |
-
* Better addslashes for SQL queries.
|
584 |
-
* Taken from phpMyAdmin.
|
585 |
-
*
|
586 |
-
* @param string $a_string
|
587 |
-
* @param bool $is_like
|
588 |
-
*
|
589 |
-
* @return mixed
|
590 |
-
*/
|
591 |
-
private function sql_addslashes( $a_string = '', $is_like = false ) {
|
592 |
-
|
593 |
-
if ( $is_like ) {
|
594 |
-
$a_string = str_replace( '\\', '\\\\\\\\', $a_string );
|
595 |
-
} else {
|
596 |
-
$a_string = str_replace( '\\', '\\\\', $a_string );
|
597 |
-
}
|
598 |
-
|
599 |
-
return str_replace( '\'', '\\\'', $a_string );
|
600 |
-
}
|
601 |
-
|
602 |
-
/**
|
603 |
-
* Close Resource
|
604 |
-
*
|
605 |
-
* @param $fp
|
606 |
-
*/
|
607 |
-
private function close( $fp ) {
|
608 |
-
|
609 |
-
fclose( $fp );
|
610 |
-
}
|
611 |
-
|
612 |
-
/**
|
613 |
-
* Deliver
|
614 |
-
*
|
615 |
-
* @param string $filename The name of the file to be downloaded.
|
616 |
-
* @param bool $compress If TRUE, gz compression is used.
|
617 |
-
*
|
618 |
-
* @return bool FALSE if error , has to DIE when file is delivered
|
619 |
-
*/
|
620 |
-
public function deliver_backup( $filename = '', $compress = false ) {
|
621 |
-
|
622 |
-
if ( '' === $filename ) {
|
623 |
-
return false;
|
624 |
-
}
|
625 |
-
|
626 |
-
// Build the file path.
|
627 |
-
$diskfile = $this->backup_dir . $filename;
|
628 |
-
|
629 |
-
// Let know the user why we cannot download his file.
|
630 |
-
if ( ! file_exists( $diskfile ) ) {
|
631 |
-
wp_die(
|
632 |
-
esc_html__( 'Seems was not possible to create the file for some reason.', 'search-and-replace' ),
|
633 |
-
esc_html__( 'Cannot Process the file - Search & Replace', 'search-and-replace' ),
|
634 |
-
[
|
635 |
-
'back_link' => true,
|
636 |
-
]
|
637 |
-
);
|
638 |
-
}
|
639 |
-
|
640 |
-
// Compress file if set.
|
641 |
-
if ( $compress ) {
|
642 |
-
// Gzipping may eat into memory.
|
643 |
-
$this->increase_memory();
|
644 |
-
|
645 |
-
$diskfile = $this->gzip( $diskfile );
|
646 |
-
}
|
647 |
-
|
648 |
-
// Provide file for download.
|
649 |
-
header( 'Content-Type: application/force-download' );
|
650 |
-
header( 'Content-Type: application/octet-stream' );
|
651 |
-
header( 'Content-Length: ' . filesize( $diskfile ) );
|
652 |
-
header( 'Content-Disposition: attachment; filename=' . basename( $diskfile ) );
|
653 |
-
|
654 |
-
readfile( $diskfile );
|
655 |
-
|
656 |
-
die();
|
657 |
-
}
|
658 |
-
|
659 |
-
/**
|
660 |
-
* Increase Memory
|
661 |
-
*
|
662 |
-
* @return void
|
663 |
-
*/
|
664 |
-
private function increase_memory() {
|
665 |
-
|
666 |
-
// Try upping the memory limit before gzipping.
|
667 |
-
if ( function_exists( 'memory_get_usage' ) && ( (int) @ini_get( 'memory_limit' ) < 64 ) ) {
|
668 |
-
@ini_set( 'memory_limit', '64M' );
|
669 |
-
}
|
670 |
-
}
|
671 |
-
|
672 |
-
/**
|
673 |
-
* Gzip
|
674 |
-
*
|
675 |
-
* @param string $diskfile The path of the file to compress
|
676 |
-
*
|
677 |
-
* @return string the file path compressed or not
|
678 |
-
*/
|
679 |
-
private function gzip( $diskfile ) {
|
680 |
-
|
681 |
-
// The file to serve.
|
682 |
-
$gz_diskfile = "{$diskfile}.gz";
|
683 |
-
|
684 |
-
// Always serve a fresh file.
|
685 |
-
// If file all-ready exists doesn't mean we have the same replace request.
|
686 |
-
file_exists( $gz_diskfile ) && unlink( $gz_diskfile );
|
687 |
-
|
688 |
-
// Try gzipping with an external application.
|
689 |
-
@exec( "gzip $diskfile" );
|
690 |
-
|
691 |
-
if ( file_exists( $gz_diskfile ) ) {
|
692 |
-
$diskfile = $gz_diskfile;
|
693 |
-
}
|
694 |
-
|
695 |
-
// If we are not capable of using `gzip` command, lets try something else.
|
696 |
-
if ( $diskfile !== $gz_diskfile && function_exists( 'gzencode' ) ) {
|
697 |
-
$text = file_get_contents( $diskfile );
|
698 |
-
$gz_text = gzencode( $text, 9 );
|
699 |
-
$this->fb = fopen( $gz_diskfile, 'wb' );
|
700 |
-
|
701 |
-
fwrite( $this->fp, $gz_text );
|
702 |
-
|
703 |
-
// Don't serve gzipped file if actually we encounter problem to close it.
|
704 |
-
if ( fclose( $this->fp ) ) {
|
705 |
-
unlink( $diskfile );
|
706 |
-
|
707 |
-
$diskfile = $gz_diskfile;
|
708 |
-
}
|
709 |
-
}
|
710 |
-
|
711 |
-
return $diskfile;
|
712 |
-
}
|
713 |
-
}
|
1 |
+
<?php /** @noinspection SqlNoDataSourceInspection */
|
2 |
+
|
3 |
+
namespace Inpsyde\SearchReplace\Database;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class Exporter
|
7 |
+
*
|
8 |
+
* @property bool|resource fb
|
9 |
+
* @package Inpsyde\SearchReplace\Database
|
10 |
+
*/
|
11 |
+
class Exporter {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* Stores all error messages in a WP_Error Object
|
15 |
+
*/
|
16 |
+
private $errors;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* @string The Path to the Backup Directory
|
20 |
+
*/
|
21 |
+
private $backup_dir;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* @var Replace
|
25 |
+
*/
|
26 |
+
private $replace;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @var Manager
|
30 |
+
*/
|
31 |
+
private $dbm;
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Count of rows to be replaced at a time
|
35 |
+
*
|
36 |
+
* @var int
|
37 |
+
*/
|
38 |
+
private $page_size = 100;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Stores the filename of the backup file
|
42 |
+
*/
|
43 |
+
private $backup_filename;
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Store file path.
|
47 |
+
*
|
48 |
+
* @var $fp
|
49 |
+
*/
|
50 |
+
private $fp;
|
51 |
+
|
52 |
+
/**
|
53 |
+
* Store csv data
|
54 |
+
*
|
55 |
+
* @var array
|
56 |
+
*/
|
57 |
+
private $csv_data = [];
|
58 |
+
|
59 |
+
/**
|
60 |
+
* Exporter constructor.
|
61 |
+
*
|
62 |
+
* @param Replace $replace
|
63 |
+
* @param Manager $dbm
|
64 |
+
* @param \WP_Error $wp_error
|
65 |
+
*/
|
66 |
+
public function __construct( Replace $replace, Manager $dbm, \WP_Error $wp_error ) {
|
67 |
+
|
68 |
+
$this->errors = $wp_error;
|
69 |
+
$this->backup_dir = get_temp_dir();
|
70 |
+
$this->replace = $replace;
|
71 |
+
$this->dbm = $dbm;
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Write to the backup file
|
76 |
+
*
|
77 |
+
* @param string $search
|
78 |
+
* @param string $replace
|
79 |
+
* @param array $tables The array of table names that should be exported.
|
80 |
+
* @param bool $domain_replace If set, exporter will change the domain name without leading http:// in table
|
81 |
+
* wp_blogs if we are on a multisite
|
82 |
+
* @param string $new_table_prefix
|
83 |
+
* @param null $csv
|
84 |
+
*
|
85 |
+
* @return array $report $report [ 'filename'] : Name of Backup file,
|
86 |
+
* $report[ 'errors'] : WP_Error_object,
|
87 |
+
* $report ['changes'] : Array with replacements in tables
|
88 |
+
* @throws \Throwable
|
89 |
+
*/
|
90 |
+
public function db_backup(
|
91 |
+
$search = '',
|
92 |
+
$replace = '',
|
93 |
+
$tables = [],
|
94 |
+
$domain_replace = false,
|
95 |
+
$new_table_prefix = '',
|
96 |
+
$csv = null
|
97 |
+
) {
|
98 |
+
|
99 |
+
if ( count( $tables ) < 1 ) {
|
100 |
+
$tables = $this->dbm->get_tables();
|
101 |
+
}
|
102 |
+
|
103 |
+
$report = [
|
104 |
+
'errors' => null,
|
105 |
+
'changes' => [],
|
106 |
+
'tables' => '0',
|
107 |
+
'changes_count' => '0',
|
108 |
+
'filename' => '',
|
109 |
+
];
|
110 |
+
|
111 |
+
$table_prefix = $this->dbm->get_base_prefix();
|
112 |
+
|
113 |
+
// wp_blogs needs special treatment in multisite domain replace, we need to check later if we are working on it.
|
114 |
+
$wp_blogs_table = $table_prefix . 'blogs';
|
115 |
+
|
116 |
+
$this->backup_filename = $new_table_prefix === '' ?
|
117 |
+
DB_NAME . "_$table_prefix.sql" :
|
118 |
+
DB_NAME . "_$new_table_prefix.sql";
|
119 |
+
|
120 |
+
// If the directory for the backup isn't writable, don't proceed.
|
121 |
+
// @ToDo Use WP_Filesystem() to access to the file system.
|
122 |
+
if ( ! is_writable( $this->backup_dir ) ) {
|
123 |
+
$this->errors->add( 9, esc_attr__( 'The backup directory is not writable!', 'search-and-replace' ) );
|
124 |
+
|
125 |
+
return $report;
|
126 |
+
}
|
127 |
+
|
128 |
+
$this->fp = $this->open( $this->backup_dir . $this->backup_filename );
|
129 |
+
|
130 |
+
if ( ! $this->fp ) {
|
131 |
+
$this->errors->add(
|
132 |
+
8,
|
133 |
+
esc_attr__( 'Could not open the backup file for writing!', 'search-and-replace' )
|
134 |
+
);
|
135 |
+
|
136 |
+
return $report;
|
137 |
+
}
|
138 |
+
|
139 |
+
// Begin new backup of MySql get charset. if not set assume utf8.
|
140 |
+
$charset = ( defined( 'DB_CHARSET' ) ? DB_CHARSET : 'utf8mb4' );
|
141 |
+
|
142 |
+
$this->stow( '# ' . esc_attr__( 'WordPress MySQL database backup', 'search-and-replace' ) . "\n" );
|
143 |
+
$this->stow( "#\n" );
|
144 |
+
$this->stow( '# ' . sprintf( __( 'Generated: %s', 'search-and-replace' ), date( 'l j. F Y H:i T' ) ) . "\n" );
|
145 |
+
$this->stow( '# ' . sprintf( __( 'Hostname: %s', 'search-and-replace' ), DB_HOST ) . "\n" );
|
146 |
+
$this->stow( '# ' . sprintf( __( 'Database: %s', 'search-and-replace' ), $this->backquote( DB_NAME ) ) . "\n" );
|
147 |
+
|
148 |
+
if ( '' !== $new_table_prefix ) {
|
149 |
+
$this->stow(
|
150 |
+
'# ' . sprintf(
|
151 |
+
/* translators: $1 and $2 are the name of the database. */
|
152 |
+
__( 'Changed table prefix: From %1$s to %2$s ', 'search-and-replace' ),
|
153 |
+
$table_prefix,
|
154 |
+
$new_table_prefix
|
155 |
+
)
|
156 |
+
. "\n"
|
157 |
+
);
|
158 |
+
}
|
159 |
+
|
160 |
+
$this->stow( "# --------------------------------------------------------\n" );
|
161 |
+
$this->stow( "/*!40101 SET NAMES $charset */;\n" );
|
162 |
+
$this->stow( "# --------------------------------------------------------\n" );
|
163 |
+
|
164 |
+
foreach ( $tables as $table ) {
|
165 |
+
|
166 |
+
// Count tables.
|
167 |
+
$report ['tables'] ++;
|
168 |
+
|
169 |
+
/**
|
170 |
+
* Check if we are replacing the domain in a multisite.
|
171 |
+
* If so, we replace in wp_blogs the stripped url without http(s), because the domains
|
172 |
+
* are stored without http://
|
173 |
+
*/
|
174 |
+
if ( $table === $wp_blogs_table && $domain_replace && is_multisite() ) {
|
175 |
+
$stripped_url_search = substr( $search, strpos( $search, '/' ) + 2 );
|
176 |
+
$stripped_url_replace = substr( $replace, strpos( $replace, '/' ) + 2 );
|
177 |
+
|
178 |
+
// Backup table.
|
179 |
+
$table_report = $this->backup_table(
|
180 |
+
$stripped_url_search,
|
181 |
+
$stripped_url_replace,
|
182 |
+
$table,
|
183 |
+
$new_table_prefix
|
184 |
+
);
|
185 |
+
} else {
|
186 |
+
// Backup table.
|
187 |
+
$table_report = $this->backup_table( $search, $replace, $table, $new_table_prefix, $csv );
|
188 |
+
}
|
189 |
+
|
190 |
+
// Log changes if any.
|
191 |
+
if ( 0 !== $table_report['change'] ) {
|
192 |
+
$report['changes'][ $table ] = $table_report;
|
193 |
+
|
194 |
+
$report ['changes_count'] += $table_report['change'];
|
195 |
+
}
|
196 |
+
}
|
197 |
+
|
198 |
+
$this->close( $this->fp );
|
199 |
+
|
200 |
+
// Return errors if any.
|
201 |
+
if ( count( $this->errors->get_error_codes() ) ) {
|
202 |
+
$report['errors'] = $this->errors;
|
203 |
+
}
|
204 |
+
|
205 |
+
$report ['filename'] = $this->backup_filename;
|
206 |
+
|
207 |
+
return $report;
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Open Resource
|
212 |
+
*
|
213 |
+
* @param string $filename
|
214 |
+
* @param string $mode
|
215 |
+
*
|
216 |
+
* @return bool|resource
|
217 |
+
*/
|
218 |
+
private function open( $filename = '', $mode = 'wb' ) {
|
219 |
+
|
220 |
+
if ( '' === $filename ) {
|
221 |
+
return false;
|
222 |
+
}
|
223 |
+
|
224 |
+
return @fopen( $filename, $mode );
|
225 |
+
}
|
226 |
+
|
227 |
+
/**
|
228 |
+
* writes a line to the backup file
|
229 |
+
*
|
230 |
+
* @param $query_line
|
231 |
+
*/
|
232 |
+
private function stow( $query_line ) {
|
233 |
+
|
234 |
+
if ( @fwrite( $this->fp, $query_line ) === false ) {
|
235 |
+
$this->errors->add(
|
236 |
+
4,
|
237 |
+
sprintf(
|
238 |
+
esc_attr__(
|
239 |
+
'There was an error writing a line to the backup script: %s',
|
240 |
+
'search-and-replace'
|
241 |
+
),
|
242 |
+
(int) $query_line
|
243 |
+
)
|
244 |
+
);
|
245 |
+
}
|
246 |
+
}
|
247 |
+
|
248 |
+
/**
|
249 |
+
* Back Quote
|
250 |
+
*
|
251 |
+
* Add backquotes to tables and db-names in
|
252 |
+
* SQL queries. Taken from phpMyAdmin.
|
253 |
+
*
|
254 |
+
* @param $a_name
|
255 |
+
*
|
256 |
+
* @return array|string
|
257 |
+
*/
|
258 |
+
private function backquote( $a_name ) {
|
259 |
+
|
260 |
+
if ( ! empty( $a_name ) && $a_name !== '*' ) {
|
261 |
+
if ( is_array( $a_name ) ) {
|
262 |
+
$result = [];
|
263 |
+
reset( $a_name );
|
264 |
+
foreach ( $a_name as $key => $val ) {
|
265 |
+
// while ( list( $key, $val ) = each( $a_name ) ) {
|
266 |
+
$result[ $key ] = '`' . $val . '`';
|
267 |
+
}
|
268 |
+
|
269 |
+
return $result;
|
270 |
+
}
|
271 |
+
|
272 |
+
return '`' . $a_name . '`';
|
273 |
+
}
|
274 |
+
|
275 |
+
return $a_name;
|
276 |
+
}
|
277 |
+
|
278 |
+
/**
|
279 |
+
* Backup Table
|
280 |
+
*
|
281 |
+
* Taken partially from phpMyAdmin and partially from
|
282 |
+
* Alain Wolf, Zurich - Switzerland
|
283 |
+
*
|
284 |
+
* Website: http://restkultur.ch/personal/wolf/scripts/db_backup/
|
285 |
+
* Modified by Scott Merrill (http://www.skippy.net/) to use the WordPress $wpdb object
|
286 |
+
*
|
287 |
+
* @param string $search
|
288 |
+
* @param string $replace
|
289 |
+
* @param string $table
|
290 |
+
* @param string $new_table_prefix
|
291 |
+
*
|
292 |
+
* @return array $table_report Reports the changes made to the db.
|
293 |
+
* @throws \Throwable
|
294 |
+
*/
|
295 |
+
public function backup_table( $search = '', $replace = '', $table, $new_table_prefix = '', $csv = null ) {
|
296 |
+
|
297 |
+
$table_report = [
|
298 |
+
'table_name' => $table,
|
299 |
+
'rows' => 0,
|
300 |
+
'change' => 0,
|
301 |
+
'changes' => [],
|
302 |
+
];
|
303 |
+
|
304 |
+
// Default columns values.
|
305 |
+
$defs = [];
|
306 |
+
// Integer value container.
|
307 |
+
$ints = [];
|
308 |
+
|
309 |
+
// This array is storage for maybe_serialized values. We must prevent deserialization of user supplied content.
|
310 |
+
$maybe_serialized = [];
|
311 |
+
$binaries = [];
|
312 |
+
|
313 |
+
// Do we need to replace the prefix?
|
314 |
+
$table_prefix = $this->dbm->get_base_prefix();
|
315 |
+
$new_table = $table;
|
316 |
+
|
317 |
+
if ( '' !== $new_table_prefix ) {
|
318 |
+
$new_table = $this->get_new_table_name( $table, $new_table_prefix );
|
319 |
+
}
|
320 |
+
|
321 |
+
// Create the SQL statements
|
322 |
+
$this->stow( '# --------------------------------------------------------' . "\n" );
|
323 |
+
$this->stow( '# ' . sprintf( __( 'Table: %s', 'search-and-replace' ), $this->backquote( $new_table ) ) . "\n" );
|
324 |
+
|
325 |
+
// Retrieve table structure.
|
326 |
+
$table_structure = $this->dbm->get_table_structure( $table );
|
327 |
+
|
328 |
+
if ( ! $table_structure ) {
|
329 |
+
$this->errors->add( 1, __( 'Error getting table details', 'search-and-replace' ) . ": $table" );
|
330 |
+
|
331 |
+
return $table_report;
|
332 |
+
}
|
333 |
+
|
334 |
+
$this->stow( "\n\n" );
|
335 |
+
$this->stow( "#\n" );
|
336 |
+
$this->stow(
|
337 |
+
'# ' . sprintf(
|
338 |
+
__( 'Delete any existing table %s', 'search-and-replace' ),
|
339 |
+
$this->backquote( $new_table )
|
340 |
+
) . "\n"
|
341 |
+
);
|
342 |
+
$this->stow( "#\n" );
|
343 |
+
$this->stow( "\n" );
|
344 |
+
$this->stow( 'DROP TABLE IF EXISTS ' . $this->backquote( $new_table ) . ';' . "\n" );
|
345 |
+
|
346 |
+
// Table structure
|
347 |
+
// Comment in SQL-file
|
348 |
+
$this->stow( "\n\n" );
|
349 |
+
$this->stow( "#\n" );
|
350 |
+
$this->stow(
|
351 |
+
'# ' . sprintf(
|
352 |
+
__( 'Table structure of table %s', 'search-and-replace' ),
|
353 |
+
$this->backquote( $new_table )
|
354 |
+
) . "\n"
|
355 |
+
);
|
356 |
+
$this->stow( "#\n" );
|
357 |
+
$this->stow( "\n" );
|
358 |
+
|
359 |
+
/** @var array $create_table */
|
360 |
+
$create_table = $this->dbm->get_create_table_statement( $table );
|
361 |
+
|
362 |
+
if ( false === $create_table ) {
|
363 |
+
/* translators: $1 is the name of the table */
|
364 |
+
$err_msg = sprintf( __( 'Error with SHOW CREATE TABLE for %s.', 'search-and-replace' ), $table );
|
365 |
+
$this->errors->add( 2, $err_msg );
|
366 |
+
$this->stow( "#\n# $err_msg\n#\n" );
|
367 |
+
}
|
368 |
+
|
369 |
+
// Replace prefix if necessary
|
370 |
+
if ( '' !== $new_table_prefix ) {
|
371 |
+
$create_table[0][1] = str_replace( $table, $new_table, $create_table[0][1] );
|
372 |
+
$table_report['new_table_name'] = $new_table;
|
373 |
+
}
|
374 |
+
|
375 |
+
$this->stow( $create_table[0][1] . ' ;' );
|
376 |
+
|
377 |
+
if ( false === $table_structure ) {
|
378 |
+
/* translators: $1 is the name of the table */
|
379 |
+
$err_msg = sprintf( __( 'Error getting table structure of %s', 'search-and-replace' ), $table );
|
380 |
+
$this->errors->add( 3, $err_msg );
|
381 |
+
$this->stow( "#\n# $err_msg\n#\n" );
|
382 |
+
}
|
383 |
+
|
384 |
+
// Comment in SQL-file
|
385 |
+
$this->stow( "\n\n" );
|
386 |
+
$this->stow( "#\n" );
|
387 |
+
$this->stow(
|
388 |
+
/* translators: $1 is the name of the new table */
|
389 |
+
'# ' . sprintf( __( 'Data contents of table %s', 'search-and-replace' ), $this->backquote( $new_table ) ) .
|
390 |
+
"\n"
|
391 |
+
);
|
392 |
+
$this->stow( "#\n" );
|
393 |
+
|
394 |
+
foreach ( $table_structure as $struct ) {
|
395 |
+
if ( 0 === strpos( $struct->Type, 'tinyint' )
|
396 |
+
|| 0 === stripos( $struct->Type, 'smallint' )
|
397 |
+
|| 0 === stripos( $struct->Type, 'mediumint' )
|
398 |
+
|| 0 === stripos( $struct->Type, 'int' )
|
399 |
+
|| 0 === stripos( $struct->Type, 'bigint' )
|
400 |
+
) {
|
401 |
+
$defs[ strtolower( $struct->Field ) ] = ( null === $struct->Default ) ? 'NULL' : $struct->Default;
|
402 |
+
$ints[ strtolower( $struct->Field ) ] = '1';
|
403 |
+
|
404 |
+
} elseif ( 0 === stripos( $struct->Type, 'binary' )
|
405 |
+
|| 0 === stripos( $struct->Type, 'varbinary' )
|
406 |
+
|| 0 === stripos( $struct->Type, 'blob' )
|
407 |
+
|| 0 === stripos( $struct->Type, 'tinyblob' )
|
408 |
+
|| 0 === stripos( $struct->Type, 'mediumblob' )
|
409 |
+
|| 0 === stripos( $struct->Type, 'longblob' )
|
410 |
+
) {
|
411 |
+
$binaries[ strtolower( $struct->Field ) ] = 1;
|
412 |
+
}
|
413 |
+
|
414 |
+
// Longtext is used for meta_values as best practice in all of the automatic products.
|
415 |
+
if ( 0 === stripos( $struct->Type, 'longtext' ) ) {
|
416 |
+
$maybe_serialized[] = strtolower( $struct->Field );
|
417 |
+
}
|
418 |
+
}
|
419 |
+
|
420 |
+
// Split columns array in primary key string and columns array.
|
421 |
+
$columns = $this->dbm->get_columns( $table );
|
422 |
+
$primary_key = $columns[0];
|
423 |
+
$row_count = $this->dbm->get_rows( $table );
|
424 |
+
$page_size = $this->page_size;
|
425 |
+
$pages = ceil( $row_count / $page_size );
|
426 |
+
|
427 |
+
// Prepare CSV data.
|
428 |
+
if ( $csv !== null ) {
|
429 |
+
$csv_lines = explode( "\n", $csv );
|
430 |
+
$csv_head = str_getcsv( 'search,replace' );
|
431 |
+
|
432 |
+
foreach ( $csv_lines as $line ) {
|
433 |
+
$this->csv_data[] = array_combine( $csv_head, str_getcsv( $line ) );
|
434 |
+
}
|
435 |
+
}
|
436 |
+
|
437 |
+
for ( $page = 0; $page < $pages; $page ++ ) {
|
438 |
+
$start = $page * $page_size;
|
439 |
+
|
440 |
+
$table_data = $this->dbm->get_table_content( $table, $start, $page_size );
|
441 |
+
|
442 |
+
$entries = 'INSERT INTO ' . $this->backquote( $new_table ) . ' VALUES (';
|
443 |
+
// \x08\\x09, not required
|
444 |
+
$hex_search = [ "\x00", "\x0a", "\x0d", "\x1a" ];
|
445 |
+
$hex_replace = [ '\0', '\n', '\r', '\Z' ];
|
446 |
+
|
447 |
+
if ( $table_data ) :
|
448 |
+
foreach ( $table_data as $row ) :
|
449 |
+
$values = [];
|
450 |
+
$table_report['rows'] ++;
|
451 |
+
|
452 |
+
foreach ( $row as $column => $value ) :
|
453 |
+
// If "change database prefix" is set we have to look for occurrences of the old prefix
|
454 |
+
// in the db entries and change them.
|
455 |
+
if ( $new_table !== $table ) {
|
456 |
+
// Check if column is expected to hold serialized value.
|
457 |
+
if ( is_serialized( $value, false )
|
458 |
+
&& in_array( strtolower( $column ), $maybe_serialized, true )
|
459 |
+
) {
|
460 |
+
$value = $this->replace->recursive_unserialize_replace(
|
461 |
+
$table_prefix,
|
462 |
+
$new_table_prefix,
|
463 |
+
$value
|
464 |
+
);
|
465 |
+
} else {
|
466 |
+
$value = str_replace( $table_prefix, $new_table_prefix, $value );
|
467 |
+
}
|
468 |
+
}
|
469 |
+
|
470 |
+
// Skip replace if no search pattern
|
471 |
+
// Check if we need to replace something
|
472 |
+
// Skip primary_key
|
473 |
+
// Skip `guid` column https://codex.wordpress.org/Changing_The_Site_URL#Important_GUID_Note
|
474 |
+
if ( $column !== $primary_key && $column !== 'guid' ) {
|
475 |
+
// Initialize
|
476 |
+
$edited_data = '';
|
477 |
+
|
478 |
+
if ( '' !== $search ) {
|
479 |
+
// Check if column is expected to hold serialized value.
|
480 |
+
if ( is_serialized( $value, false )
|
481 |
+
&& in_array( strtolower( $column ), $maybe_serialized, true )
|
482 |
+
) {
|
483 |
+
$edited_data = $this->replace->recursive_unserialize_replace(
|
484 |
+
$search,
|
485 |
+
$replace,
|
486 |
+
$value
|
487 |
+
);
|
488 |
+
} else {
|
489 |
+
$edited_data = str_replace( $search, $replace, $value );
|
490 |
+
}
|
491 |
+
}
|
492 |
+
|
493 |
+
// If csv string has passed let's replace those values.
|
494 |
+
if ( $csv !== null ) {
|
495 |
+
foreach ( $this->csv_data as $entry ) {
|
496 |
+
$edited_data = is_serialized( $edited_data, false ) ?
|
497 |
+
$this->replace->recursive_unserialize_replace(
|
498 |
+
$entry['search'],
|
499 |
+
$entry['replace'],
|
500 |
+
$edited_data
|
501 |
+
) : str_replace( $entry['search'], $entry['replace'], $value );
|
502 |
+
}
|
503 |
+
}
|
504 |
+
|
505 |
+
// When a replace happen, update the table report.
|
506 |
+
if ( $edited_data && $edited_data !== $value ) {
|
507 |
+
$table_report['change'] ++;
|
508 |
+
|
509 |
+
// log changes
|
510 |
+
$table_report['changes'][] = [
|
511 |
+
'row' => $table_report['rows'],
|
512 |
+
'column' => $column,
|
513 |
+
'from' => $value,
|
514 |
+
'to' => $edited_data,
|
515 |
+
];
|
516 |
+
|
517 |
+
$value = $edited_data;
|
518 |
+
}
|
519 |
+
}
|
520 |
+
|
521 |
+
if ( isset( $ints[ strtolower( $column ) ] ) ) {
|
522 |
+
// make sure there are no blank spots in the insert syntax,
|
523 |
+
// yet try to avoid quotation marks around integers
|
524 |
+
$value = ( null === $value || '' === $value ) ? $defs[ strtolower( $column ) ] : $value;
|
525 |
+
$values[] = ( '' === $value ) ? "''" : $value;
|
526 |
+
} else if ( isset( $binaries[ strtolower( $column ) ] ) ) {
|
527 |
+
$hex = unpack( 'H*', $value );
|
528 |
+
$values[] = "0x$hex[1]";
|
529 |
+
} else {
|
530 |
+
$values[] = "'" . str_replace(
|
531 |
+
$hex_search,
|
532 |
+
$hex_replace,
|
533 |
+
$this->sql_addslashes( $value )
|
534 |
+
) . "'";
|
535 |
+
}
|
536 |
+
endforeach;
|
537 |
+
|
538 |
+
$this->stow( " \n" . $entries . implode( ', ', $values ) . ');' );
|
539 |
+
|
540 |
+
endforeach;
|
541 |
+
endif;
|
542 |
+
}
|
543 |
+
|
544 |
+
// Create footer/closing comment in SQL-file
|
545 |
+
$this->stow( "\n" );
|
546 |
+
$this->stow( "#\n" );
|
547 |
+
$this->stow(
|
548 |
+
'# ' . sprintf(
|
549 |
+
/* translators: $1 is the name of the table */
|
550 |
+
__( 'End of data contents of table %s', 'search-and-replace' ),
|
551 |
+
$this->backquote( $new_table )
|
552 |
+
) . "\n"
|
553 |
+
);
|
554 |
+
$this->stow( "# --------------------------------------------------------\n" );
|
555 |
+
$this->stow( "\n" );
|
556 |
+
|
557 |
+
return $table_report;
|
558 |
+
}
|
559 |
+
|
560 |
+
/**
|
561 |
+
* Get new Table name
|
562 |
+
*
|
563 |
+
* strips the current table prefix and adds a new one provided in $new_table_prefix
|
564 |
+
*
|
565 |
+
* @param $table
|
566 |
+
* @param $new_table_prefix
|
567 |
+
*
|
568 |
+
* @return string The table name with new prefix
|
569 |
+
*/
|
570 |
+
private function get_new_table_name( $table, $new_table_prefix ) {
|
571 |
+
|
572 |
+
// Get length of base_prefix
|
573 |
+
$prefix = $this->dbm->get_base_prefix();
|
574 |
+
$prefix_length = strlen( $prefix );
|
575 |
+
// Strip old prefix
|
576 |
+
$part_after_prefix = substr( $table, $prefix_length );
|
577 |
+
|
578 |
+
// Build new table name
|
579 |
+
return $new_table_prefix . $part_after_prefix;
|
580 |
+
}
|
581 |
+
|
582 |
+
/**
|
583 |
+
* Better addslashes for SQL queries.
|
584 |
+
* Taken from phpMyAdmin.
|
585 |
+
*
|
586 |
+
* @param string $a_string
|
587 |
+
* @param bool $is_like
|
588 |
+
*
|
589 |
+
* @return mixed
|
590 |
+
*/
|
591 |
+
private function sql_addslashes( $a_string = '', $is_like = false ) {
|
592 |
+
|
593 |
+
if ( $is_like ) {
|
594 |
+
$a_string = str_replace( '\\', '\\\\\\\\', $a_string );
|
595 |
+
} else {
|
596 |
+
$a_string = str_replace( '\\', '\\\\', $a_string );
|
597 |
+
}
|
598 |
+
|
599 |
+
return str_replace( '\'', '\\\'', $a_string );
|
600 |
+
}
|
601 |
+
|
602 |
+
/**
|
603 |
+
* Close Resource
|
604 |
+
*
|
605 |
+
* @param $fp
|
606 |
+
*/
|
607 |
+
private function close( $fp ) {
|
608 |
+
|
609 |
+
fclose( $fp );
|
610 |
+
}
|
611 |
+
|
612 |
+
/**
|
613 |
+
* Deliver
|
614 |
+
*
|
615 |
+
* @param string $filename The name of the file to be downloaded.
|
616 |
+
* @param bool $compress If TRUE, gz compression is used.
|
617 |
+
*
|
618 |
+
* @return bool FALSE if error , has to DIE when file is delivered
|
619 |
+
*/
|
620 |
+
public function deliver_backup( $filename = '', $compress = false ) {
|
621 |
+
|
622 |
+
if ( '' === $filename ) {
|
623 |
+
return false;
|
624 |
+
}
|
625 |
+
|
626 |
+
// Build the file path.
|
627 |
+
$diskfile = $this->backup_dir . $filename;
|
628 |
+
|
629 |
+
// Let know the user why we cannot download his file.
|
630 |
+
if ( ! file_exists( $diskfile ) ) {
|
631 |
+
wp_die(
|
632 |
+
esc_html__( 'Seems was not possible to create the file for some reason.', 'search-and-replace' ),
|
633 |
+
esc_html__( 'Cannot Process the file - Search & Replace', 'search-and-replace' ),
|
634 |
+
[
|
635 |
+
'back_link' => true,
|
636 |
+
]
|
637 |
+
);
|
638 |
+
}
|
639 |
+
|
640 |
+
// Compress file if set.
|
641 |
+
if ( $compress ) {
|
642 |
+
// Gzipping may eat into memory.
|
643 |
+
$this->increase_memory();
|
644 |
+
|
645 |
+
$diskfile = $this->gzip( $diskfile );
|
646 |
+
}
|
647 |
+
|
648 |
+
// Provide file for download.
|
649 |
+
header( 'Content-Type: application/force-download' );
|
650 |
+
header( 'Content-Type: application/octet-stream' );
|
651 |
+
header( 'Content-Length: ' . filesize( $diskfile ) );
|
652 |
+
header( 'Content-Disposition: attachment; filename=' . basename( $diskfile ) );
|
653 |
+
|
654 |
+
readfile( $diskfile );
|
655 |
+
|
656 |
+
die();
|
657 |
+
}
|
658 |
+
|
659 |
+
/**
|
660 |
+
* Increase Memory
|
661 |
+
*
|
662 |
+
* @return void
|
663 |
+
*/
|
664 |
+
private function increase_memory() {
|
665 |
+
|
666 |
+
// Try upping the memory limit before gzipping.
|
667 |
+
if ( function_exists( 'memory_get_usage' ) && ( (int) @ini_get( 'memory_limit' ) < 64 ) ) {
|
668 |
+
@ini_set( 'memory_limit', '64M' );
|
669 |
+
}
|
670 |
+
}
|
671 |
+
|
672 |
+
/**
|
673 |
+
* Gzip
|
674 |
+
*
|
675 |
+
* @param string $diskfile The path of the file to compress
|
676 |
+
*
|
677 |
+
* @return string the file path compressed or not
|
678 |
+
*/
|
679 |
+
private function gzip( $diskfile ) {
|
680 |
+
|
681 |
+
// The file to serve.
|
682 |
+
$gz_diskfile = "{$diskfile}.gz";
|
683 |
+
|
684 |
+
// Always serve a fresh file.
|
685 |
+
// If file all-ready exists doesn't mean we have the same replace request.
|
686 |
+
file_exists( $gz_diskfile ) && unlink( $gz_diskfile );
|
687 |
+
|
688 |
+
// Try gzipping with an external application.
|
689 |
+
@exec( "gzip $diskfile" );
|
690 |
+
|
691 |
+
if ( file_exists( $gz_diskfile ) ) {
|
692 |
+
$diskfile = $gz_diskfile;
|
693 |
+
}
|
694 |
+
|
695 |
+
// If we are not capable of using `gzip` command, lets try something else.
|
696 |
+
if ( $diskfile !== $gz_diskfile && function_exists( 'gzencode' ) ) {
|
697 |
+
$text = file_get_contents( $diskfile );
|
698 |
+
$gz_text = gzencode( $text, 9 );
|
699 |
+
$this->fb = fopen( $gz_diskfile, 'wb' );
|
700 |
+
|
701 |
+
fwrite( $this->fp, $gz_text );
|
702 |
+
|
703 |
+
// Don't serve gzipped file if actually we encounter problem to close it.
|
704 |
+
if ( fclose( $this->fp ) ) {
|
705 |
+
unlink( $diskfile );
|
706 |
+
|
707 |
+
$diskfile = $gz_diskfile;
|
708 |
+
}
|
709 |
+
}
|
710 |
+
|
711 |
+
return $diskfile;
|
712 |
+
}
|
713 |
+
}
|
inc/Database/Importer.php
CHANGED
@@ -1,64 +1,64 @@
|
|
1 |
-
<?php
|
2 |
-
namespace Inpsyde\SearchReplace\Database;
|
3 |
-
|
4 |
-
use Inpsyde\SearchReplace\Service\MaxExecutionTime;
|
5 |
-
|
6 |
-
/**
|
7 |
-
* Class Importer
|
8 |
-
*
|
9 |
-
* @package Inpsyde\SearchReplace\Database
|
10 |
-
*/
|
11 |
-
class Importer {
|
12 |
-
|
13 |
-
/**
|
14 |
-
* @var MaxExecutionTime
|
15 |
-
*/
|
16 |
-
private $max_execution;
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Importer constructor.
|
20 |
-
*
|
21 |
-
* @param MaxExecutionTime $max_execution
|
22 |
-
*/
|
23 |
-
public function __construct( MaxExecutionTime $max_execution ) {
|
24 |
-
$this->max_execution = $max_execution;
|
25 |
-
}
|
26 |
-
|
27 |
-
/**
|
28 |
-
* Imports a sql file via mysqli
|
29 |
-
*
|
30 |
-
* @param string $sql
|
31 |
-
*
|
32 |
-
* @return int Number of Sql queries made, -1 if error
|
33 |
-
*/
|
34 |
-
public function import_sql( $sql ) {
|
35 |
-
|
36 |
-
$this->max_execution->set();
|
37 |
-
|
38 |
-
// connect via mysqli for easier db import
|
39 |
-
$mysqli = new \mysqli( DB_HOST, DB_USER, DB_PASSWORD, DB_NAME );
|
40 |
-
|
41 |
-
// Run the SQL
|
42 |
-
$i = 1;
|
43 |
-
if ( $mysqli->multi_query( $sql ) ) {
|
44 |
-
do {
|
45 |
-
if ( $mysqli->more_results() ) {
|
46 |
-
$mysqli->next_result();
|
47 |
-
|
48 |
-
$i ++;
|
49 |
-
}
|
50 |
-
} while ( $mysqli->more_results() );
|
51 |
-
}
|
52 |
-
|
53 |
-
if ( $mysqli->errno ) {
|
54 |
-
return - 1;
|
55 |
-
}
|
56 |
-
|
57 |
-
mysqli_close( $mysqli );
|
58 |
-
|
59 |
-
$this->max_execution->restore();
|
60 |
-
|
61 |
-
return $i;
|
62 |
-
}
|
63 |
-
|
64 |
-
}
|
1 |
+
<?php
|
2 |
+
namespace Inpsyde\SearchReplace\Database;
|
3 |
+
|
4 |
+
use Inpsyde\SearchReplace\Service\MaxExecutionTime;
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Class Importer
|
8 |
+
*
|
9 |
+
* @package Inpsyde\SearchReplace\Database
|
10 |
+
*/
|
11 |
+
class Importer {
|
12 |
+
|
13 |
+
/**
|
14 |
+
* @var MaxExecutionTime
|
15 |
+
*/
|
16 |
+
private $max_execution;
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Importer constructor.
|
20 |
+
*
|
21 |
+
* @param MaxExecutionTime $max_execution
|
22 |
+
*/
|
23 |
+
public function __construct( MaxExecutionTime $max_execution ) {
|
24 |
+
$this->max_execution = $max_execution;
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Imports a sql file via mysqli
|
29 |
+
*
|
30 |
+
* @param string $sql
|
31 |
+
*
|
32 |
+
* @return int Number of Sql queries made, -1 if error
|
33 |
+
*/
|
34 |
+
public function import_sql( $sql ) {
|
35 |
+
|
36 |
+
$this->max_execution->set();
|
37 |
+
|
38 |
+
// connect via mysqli for easier db import
|
39 |
+
$mysqli = new \mysqli( DB_HOST, DB_USER, DB_PASSWORD, DB_NAME );
|
40 |
+
|
41 |
+
// Run the SQL
|
42 |
+
$i = 1;
|
43 |
+
if ( $mysqli->multi_query( $sql ) ) {
|
44 |
+
do {
|
45 |
+
if ( $mysqli->more_results() ) {
|
46 |
+
$mysqli->next_result();
|
47 |
+
|
48 |
+
$i ++;
|
49 |
+
}
|
50 |
+
} while ( $mysqli->more_results() );
|
51 |
+
}
|
52 |
+
|
53 |
+
if ( $mysqli->errno ) {
|
54 |
+
return - 1;
|
55 |
+
}
|
56 |
+
|
57 |
+
mysqli_close( $mysqli );
|
58 |
+
|
59 |
+
$this->max_execution->restore();
|
60 |
+
|
61 |
+
return $i;
|
62 |
+
}
|
63 |
+
|
64 |
+
}
|
inc/Database/Manager.php
CHANGED
@@ -1,200 +1,200 @@
|
|
1 |
-
<?php
|
2 |
-
/** @noinspection SqlDialectInspection */
|
3 |
-
/** @noinspection SqlNoDataSourceInspection */
|
4 |
-
|
5 |
-
namespace Inpsyde\SearchReplace\Database;
|
6 |
-
|
7 |
-
/**
|
8 |
-
* Class Manager
|
9 |
-
*
|
10 |
-
* @package Inpsyde\SearchReplace\Database
|
11 |
-
*/
|
12 |
-
class Manager {
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @var \wpdb
|
16 |
-
* WordPress Database Class.
|
17 |
-
* some functions adapted from :
|
18 |
-
* https://github.com/ExpandedFronts/Better-Search-Replace/blob/master/includes/class-bsr-db.php
|
19 |
-
*/
|
20 |
-
private $wpdb;
|
21 |
-
|
22 |
-
/**
|
23 |
-
* DatabaseManager constructor.
|
24 |
-
*
|
25 |
-
* @param \wpdb $wpdb
|
26 |
-
*/
|
27 |
-
public function __construct( \wpdb $wpdb ) {
|
28 |
-
|
29 |
-
$this->wpdb = $wpdb;
|
30 |
-
}
|
31 |
-
|
32 |
-
/**
|
33 |
-
* Returns an array of tables in the database.
|
34 |
-
* if multisite && mainsite: all tables of the site
|
35 |
-
* if multisite && subsite: all tables of current blog
|
36 |
-
* if single site : all tabkes of the site
|
37 |
-
*
|
38 |
-
* @access public
|
39 |
-
* @return array
|
40 |
-
*/
|
41 |
-
public function get_tables() {
|
42 |
-
|
43 |
-
if ( function_exists( 'is_multisite' ) && is_multisite() ) {
|
44 |
-
|
45 |
-
if ( is_main_site() ) {
|
46 |
-
$tables = $this->wpdb->get_col( "SHOW TABLES LIKE'" . $this->wpdb->base_prefix . "%'" );
|
47 |
-
} else {
|
48 |
-
$blog_id = get_current_blog_id();
|
49 |
-
$tables = $this->wpdb->get_col(
|
50 |
-
"SHOW TABLES LIKE '" . $this->wpdb->base_prefix . absint( $blog_id ) . "\_%'"
|
51 |
-
);
|
52 |
-
}
|
53 |
-
|
54 |
-
} else {
|
55 |
-
$tables = $this->wpdb->get_col( "SHOW TABLES LIKE'" . $this->wpdb->base_prefix . "%'" );
|
56 |
-
}
|
57 |
-
|
58 |
-
return $tables;
|
59 |
-
}
|
60 |
-
|
61 |
-
/**
|
62 |
-
* Returns an array containing the size of each database table.
|
63 |
-
*
|
64 |
-
* @access public
|
65 |
-
* @return array Table => Table Size in KB
|
66 |
-
*/
|
67 |
-
public function get_sizes() {
|
68 |
-
|
69 |
-
$sizes = array();
|
70 |
-
$tables = $this->wpdb->get_results( 'SHOW TABLE STATUS', ARRAY_A );
|
71 |
-
|
72 |
-
if ( is_array( $tables ) && ! empty( $tables ) ) {
|
73 |
-
|
74 |
-
foreach ( $tables as $table ) {
|
75 |
-
$size = round( $table[ 'Data_length' ] / 1024, 2 );
|
76 |
-
// Translators: %s is the value of the size in kByte.
|
77 |
-
$sizes[ $table[ 'Name' ] ] = sprintf( __( '(%s KB)', 'search-and-replace' ), $size );
|
78 |
-
}
|
79 |
-
}
|
80 |
-
|
81 |
-
return $sizes;
|
82 |
-
}
|
83 |
-
|
84 |
-
/**
|
85 |
-
* Returns the number of rows in a table.
|
86 |
-
*
|
87 |
-
* @access public
|
88 |
-
*
|
89 |
-
* @param array|string $table
|
90 |
-
*
|
91 |
-
* @return int
|
92 |
-
*/
|
93 |
-
public function get_rows( $table ) {
|
94 |
-
|
95 |
-
$table = esc_sql( $table );
|
96 |
-
|
97 |
-
return $this->wpdb->get_var( "SELECT COUNT(*) FROM $table" );
|
98 |
-
}
|
99 |
-
|
100 |
-
/**
|
101 |
-
* Gets the columns in a table.
|
102 |
-
*
|
103 |
-
* @access public
|
104 |
-
*
|
105 |
-
* @param string $table The table to check.
|
106 |
-
*
|
107 |
-
* @return array 1st Element: Primary Key, 2nd Element All Columns
|
108 |
-
*/
|
109 |
-
public function get_columns( $table ) {
|
110 |
-
|
111 |
-
$primary_key = null;
|
112 |
-
$columns = array();
|
113 |
-
$fields = $this->wpdb->get_results( 'DESCRIBE ' . $table );
|
114 |
-
|
115 |
-
if ( is_array( $fields ) ) {
|
116 |
-
foreach ( $fields as $column ) {
|
117 |
-
$columns[] = $column->Field;
|
118 |
-
if ( 'PRI' === $column->Key ) {
|
119 |
-
$primary_key = $column->Field;
|
120 |
-
}
|
121 |
-
}
|
122 |
-
}
|
123 |
-
|
124 |
-
return array( $primary_key, $columns );
|
125 |
-
}
|
126 |
-
|
127 |
-
/**
|
128 |
-
* @param string $table The Table Name.
|
129 |
-
* @param integer $start The start row.
|
130 |
-
* @param integer $end Int Number of Rows to be fetched.
|
131 |
-
*
|
132 |
-
* @return array|null|object
|
133 |
-
*/
|
134 |
-
public function get_table_content( $table, $start, $end ) {
|
135 |
-
|
136 |
-
$data = $this->wpdb->get_results( "SELECT * FROM $table LIMIT $start, $end", ARRAY_A );
|
137 |
-
|
138 |
-
return $data;
|
139 |
-
}
|
140 |
-
|
141 |
-
/**
|
142 |
-
* Update table.
|
143 |
-
*
|
144 |
-
* @param string $table
|
145 |
-
* @param array $update_sql
|
146 |
-
* @param array $where_sql
|
147 |
-
*
|
148 |
-
* @return false|int
|
149 |
-
*/
|
150 |
-
public function update( $table, $update_sql, $where_sql ) {
|
151 |
-
|
152 |
-
$sql = 'UPDATE ' . $table . ' SET ' . implode( ', ', $update_sql ) .
|
153 |
-
' WHERE ' . implode( ' AND ', array_filter( $where_sql ) );
|
154 |
-
|
155 |
-
return $this->wpdb->query( $sql );
|
156 |
-
}
|
157 |
-
|
158 |
-
/**
|
159 |
-
* Get table structure.
|
160 |
-
*
|
161 |
-
* @param string $table
|
162 |
-
*
|
163 |
-
* @return array|null|object
|
164 |
-
*/
|
165 |
-
public function get_table_structure( $table ) {
|
166 |
-
|
167 |
-
return $this->wpdb->get_results( "DESCRIBE $table" );
|
168 |
-
}
|
169 |
-
|
170 |
-
/**
|
171 |
-
* Returns a SQL CREATE TABLE Statement for the table provided in $table.
|
172 |
-
*
|
173 |
-
* @param string $table String The Name of the table we want to create the statement for.
|
174 |
-
*
|
175 |
-
* @return string
|
176 |
-
*/
|
177 |
-
public function get_create_table_statement( $table ) {
|
178 |
-
|
179 |
-
return $this->wpdb->get_results( "SHOW CREATE TABLE $table", ARRAY_N );
|
180 |
-
}
|
181 |
-
|
182 |
-
/**
|
183 |
-
* Flush table.
|
184 |
-
*/
|
185 |
-
public function flush() {
|
186 |
-
|
187 |
-
$this->wpdb->flush();
|
188 |
-
}
|
189 |
-
|
190 |
-
/**
|
191 |
-
* Get base prefix.
|
192 |
-
*
|
193 |
-
* @return string
|
194 |
-
*/
|
195 |
-
public function get_base_prefix() {
|
196 |
-
|
197 |
-
return $this->wpdb->base_prefix;
|
198 |
-
}
|
199 |
-
|
200 |
-
}
|
1 |
+
<?php
|
2 |
+
/** @noinspection SqlDialectInspection */
|
3 |
+
/** @noinspection SqlNoDataSourceInspection */
|
4 |
+
|
5 |
+
namespace Inpsyde\SearchReplace\Database;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Class Manager
|
9 |
+
*
|
10 |
+
* @package Inpsyde\SearchReplace\Database
|
11 |
+
*/
|
12 |
+
class Manager {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @var \wpdb
|
16 |
+
* WordPress Database Class.
|
17 |
+
* some functions adapted from :
|
18 |
+
* https://github.com/ExpandedFronts/Better-Search-Replace/blob/master/includes/class-bsr-db.php
|
19 |
+
*/
|
20 |
+
private $wpdb;
|
21 |
+
|
22 |
+
/**
|
23 |
+
* DatabaseManager constructor.
|
24 |
+
*
|
25 |
+
* @param \wpdb $wpdb
|
26 |
+
*/
|
27 |
+
public function __construct( \wpdb $wpdb ) {
|
28 |
+
|
29 |
+
$this->wpdb = $wpdb;
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Returns an array of tables in the database.
|
34 |
+
* if multisite && mainsite: all tables of the site
|
35 |
+
* if multisite && subsite: all tables of current blog
|
36 |
+
* if single site : all tabkes of the site
|
37 |
+
*
|
38 |
+
* @access public
|
39 |
+
* @return array
|
40 |
+
*/
|
41 |
+
public function get_tables() {
|
42 |
+
|
43 |
+
if ( function_exists( 'is_multisite' ) && is_multisite() ) {
|
44 |
+
|
45 |
+
if ( is_main_site() ) {
|
46 |
+
$tables = $this->wpdb->get_col( "SHOW TABLES LIKE'" . $this->wpdb->base_prefix . "%'" );
|
47 |
+
} else {
|
48 |
+
$blog_id = get_current_blog_id();
|
49 |
+
$tables = $this->wpdb->get_col(
|
50 |
+
"SHOW TABLES LIKE '" . $this->wpdb->base_prefix . absint( $blog_id ) . "\_%'"
|
51 |
+
);
|
52 |
+
}
|
53 |
+
|
54 |
+
} else {
|
55 |
+
$tables = $this->wpdb->get_col( "SHOW TABLES LIKE'" . $this->wpdb->base_prefix . "%'" );
|
56 |
+
}
|
57 |
+
|
58 |
+
return $tables;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Returns an array containing the size of each database table.
|
63 |
+
*
|
64 |
+
* @access public
|
65 |
+
* @return array Table => Table Size in KB
|
66 |
+
*/
|
67 |
+
public function get_sizes() {
|
68 |
+
|
69 |
+
$sizes = array();
|
70 |
+
$tables = $this->wpdb->get_results( 'SHOW TABLE STATUS', ARRAY_A );
|
71 |
+
|
72 |
+
if ( is_array( $tables ) && ! empty( $tables ) ) {
|
73 |
+
|
74 |
+
foreach ( $tables as $table ) {
|
75 |
+
$size = round( $table[ 'Data_length' ] / 1024, 2 );
|
76 |
+
// Translators: %s is the value of the size in kByte.
|
77 |
+
$sizes[ $table[ 'Name' ] ] = sprintf( __( '(%s KB)', 'search-and-replace' ), $size );
|
78 |
+
}
|
79 |
+
}
|
80 |
+
|
81 |
+
return $sizes;
|
82 |
+
}
|
83 |
+
|
84 |
+
/**
|
85 |
+
* Returns the number of rows in a table.
|
86 |
+
*
|
87 |
+
* @access public
|
88 |
+
*
|
89 |
+
* @param array|string $table
|
90 |
+
*
|
91 |
+
* @return int
|
92 |
+
*/
|
93 |
+
public function get_rows( $table ) {
|
94 |
+
|
95 |
+
$table = esc_sql( $table );
|
96 |
+
|
97 |
+
return $this->wpdb->get_var( "SELECT COUNT(*) FROM $table" );
|
98 |
+
}
|
99 |
+
|
100 |
+
/**
|
101 |
+
* Gets the columns in a table.
|
102 |
+
*
|
103 |
+
* @access public
|
104 |
+
*
|
105 |
+
* @param string $table The table to check.
|
106 |
+
*
|
107 |
+
* @return array 1st Element: Primary Key, 2nd Element All Columns
|
108 |
+
*/
|
109 |
+
public function get_columns( $table ) {
|
110 |
+
|
111 |
+
$primary_key = null;
|
112 |
+
$columns = array();
|
113 |
+
$fields = $this->wpdb->get_results( 'DESCRIBE ' . $table );
|
114 |
+
|
115 |
+
if ( is_array( $fields ) ) {
|
116 |
+
foreach ( $fields as $column ) {
|
117 |
+
$columns[] = $column->Field;
|
118 |
+
if ( 'PRI' === $column->Key ) {
|
119 |
+
$primary_key = $column->Field;
|
120 |
+
}
|
121 |
+
}
|
122 |
+
}
|
123 |
+
|
124 |
+
return array( $primary_key, $columns );
|
125 |
+
}
|
126 |
+
|
127 |
+
/**
|
128 |
+
* @param string $table The Table Name.
|
129 |
+
* @param integer $start The start row.
|
130 |
+
* @param integer $end Int Number of Rows to be fetched.
|
131 |
+
*
|
132 |
+
* @return array|null|object
|
133 |
+
*/
|
134 |
+
public function get_table_content( $table, $start, $end ) {
|
135 |
+
|
136 |
+
$data = $this->wpdb->get_results( "SELECT * FROM $table LIMIT $start, $end", ARRAY_A );
|
137 |
+
|
138 |
+
return $data;
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Update table.
|
143 |
+
*
|
144 |
+
* @param string $table
|
145 |
+
* @param array $update_sql
|
146 |
+
* @param array $where_sql
|
147 |
+
*
|
148 |
+
* @return false|int
|
149 |
+
*/
|
150 |
+
public function update( $table, $update_sql, $where_sql ) {
|
151 |
+
|
152 |
+
$sql = 'UPDATE ' . $table . ' SET ' . implode( ', ', $update_sql ) .
|
153 |
+
' WHERE ' . implode( ' AND ', array_filter( $where_sql ) );
|
154 |
+
|
155 |
+
return $this->wpdb->query( $sql );
|
156 |
+
}
|
157 |
+
|
158 |
+
/**
|
159 |
+
* Get table structure.
|
160 |
+
*
|
161 |
+
* @param string $table
|
162 |
+
*
|
163 |
+
* @return array|null|object
|
164 |
+
*/
|
165 |
+
public function get_table_structure( $table ) {
|
166 |
+
|
167 |
+
return $this->wpdb->get_results( "DESCRIBE $table" );
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Returns a SQL CREATE TABLE Statement for the table provided in $table.
|
172 |
+
*
|
173 |
+
* @param string $table String The Name of the table we want to create the statement for.
|
174 |
+
*
|
175 |
+
* @return string
|
176 |
+
*/
|
177 |
+
public function get_create_table_statement( $table ) {
|
178 |
+
|
179 |
+
return $this->wpdb->get_results( "SHOW CREATE TABLE $table", ARRAY_N );
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Flush table.
|
184 |
+
*/
|
185 |
+
public function flush() {
|
186 |
+
|
187 |
+
$this->wpdb->flush();
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Get base prefix.
|
192 |
+
*
|
193 |
+
* @return string
|
194 |
+
*/
|
195 |
+
public function get_base_prefix() {
|
196 |
+
|
197 |
+
return $this->wpdb->base_prefix;
|
198 |
+
}
|
199 |
+
|
200 |
+
}
|
inc/Database/Replace.php
CHANGED
@@ -1,430 +1,431 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace Inpsyde\SearchReplace\Database;
|
4 |
-
|
5 |
-
use
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
*
|
10 |
-
*
|
11 |
-
*
|
12 |
-
*
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
*
|
18 |
-
*
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
*
|
25 |
-
*
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
*
|
42 |
-
*
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
*
|
49 |
-
*
|
50 |
-
* @param
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
$this->
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
*
|
61 |
-
* walks every
|
62 |
-
*
|
63 |
-
*
|
64 |
-
*
|
65 |
-
*
|
66 |
-
* @param string $
|
67 |
-
* @param string $
|
68 |
-
* @param
|
69 |
-
*
|
70 |
-
*
|
71 |
-
* @
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
'
|
85 |
-
'
|
86 |
-
'
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
$
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
$report
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
*
|
108 |
-
*
|
109 |
-
* @param string $
|
110 |
-
* @param string $
|
111 |
-
* @param
|
112 |
-
*
|
113 |
-
*
|
114 |
-
* @
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
'
|
121 |
-
'
|
122 |
-
'
|
123 |
-
'
|
124 |
-
'
|
125 |
-
'
|
126 |
-
'
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
//
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
$
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
$
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
$
|
201 |
-
$
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
$entry['
|
233 |
-
$
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
//
|
244 |
-
|
245 |
-
|
246 |
-
'
|
247 |
-
'
|
248 |
-
'
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
$
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
*
|
290 |
-
*
|
291 |
-
* @
|
292 |
-
*
|
293 |
-
*
|
294 |
-
*
|
295 |
-
*
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
[ '
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
*
|
316 |
-
*
|
317 |
-
*
|
318 |
-
*
|
319 |
-
*
|
320 |
-
*
|
321 |
-
*
|
322 |
-
*
|
323 |
-
*
|
324 |
-
*
|
325 |
-
* @param string $
|
326 |
-
* @param
|
327 |
-
* @param
|
328 |
-
*
|
329 |
-
*
|
330 |
-
*
|
331 |
-
*
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
$
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
//
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
$
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
$
|
377 |
-
|
378 |
-
|
379 |
-
//
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
*
|
407 |
-
*
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
*
|
417 |
-
*
|
418 |
-
*
|
419 |
-
*
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
}
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Inpsyde\SearchReplace\Database;
|
4 |
+
|
5 |
+
use Exception;
|
6 |
+
use Inpsyde\SearchReplace\Service;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class Replace
|
10 |
+
* runs search & replace on a database
|
11 |
+
* adapted from: https://github.com/interconnectit/Search-Replace-DB/blob/master/srdb.class.php
|
12 |
+
*
|
13 |
+
* @package Inpsyde\SearchReplace\Database
|
14 |
+
*/
|
15 |
+
class Replace {
|
16 |
+
/**
|
17 |
+
* The Database Interface Object
|
18 |
+
*
|
19 |
+
* @var Manager
|
20 |
+
*/
|
21 |
+
private $dbm;
|
22 |
+
|
23 |
+
/**
|
24 |
+
* Count of rows to be replaced at a time
|
25 |
+
*
|
26 |
+
* @var int
|
27 |
+
*/
|
28 |
+
private $page_size = 100;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @var bool - set if dry run
|
32 |
+
*/
|
33 |
+
private $dry_run = true;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* @var Service\MaxExecutionTime
|
37 |
+
*/
|
38 |
+
private $max_execution;
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Store csv data
|
42 |
+
*
|
43 |
+
* @var array
|
44 |
+
*/
|
45 |
+
private $csv_data = [];
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Replace constructor.
|
49 |
+
*
|
50 |
+
* @param Manager $dbm
|
51 |
+
* @param Service\MaxExecutionTime $max_execution
|
52 |
+
*/
|
53 |
+
public function __construct( Manager $dbm, Service\MaxExecutionTime $max_execution ) {
|
54 |
+
|
55 |
+
$this->dbm = $dbm;
|
56 |
+
$this->max_execution = $max_execution;
|
57 |
+
}
|
58 |
+
|
59 |
+
/**
|
60 |
+
* The main loop triggered in step 5. Up here to keep it out of the way of the
|
61 |
+
* HTML. This walks every table in the db that was selected in step 3 and then
|
62 |
+
* walks every row and column replacing all occurrences of a string with another.
|
63 |
+
* We split large tables into blocks (size is set via $page_size)when dealing with them to save
|
64 |
+
* on memory consumption.
|
65 |
+
*
|
66 |
+
* @param string $search What we want to replace.
|
67 |
+
* @param string $replace What we want to replace it with.
|
68 |
+
* @param string $tables The name of the table we want to look at.
|
69 |
+
* @param null $csv
|
70 |
+
*
|
71 |
+
* @return array|\WP_Error Collection of information gathered during the run.
|
72 |
+
* @throws \Throwable
|
73 |
+
*/
|
74 |
+
|
75 |
+
public function run_search_replace( $search, $replace, $tables, $csv = null ) {
|
76 |
+
|
77 |
+
if ( $search === $replace && '' !== $search ) {
|
78 |
+
return new \WP_Error( 'error', esc_html__( 'Search and replace pattern can\'t be the same!', 'search-and-replace' ) );
|
79 |
+
}
|
80 |
+
|
81 |
+
$this->max_execution->set();
|
82 |
+
|
83 |
+
$report = [
|
84 |
+
'errors' => null,
|
85 |
+
'changes' => [],
|
86 |
+
'tables' => '0',
|
87 |
+
'changes_count' => '0',
|
88 |
+
];
|
89 |
+
|
90 |
+
foreach ( (array) $tables as $table ) {
|
91 |
+
// Count tables.
|
92 |
+
$report ['tables'] ++;
|
93 |
+
$table_report = $this->replace_values( $search, $replace, $table, $csv );
|
94 |
+
// Log changes if any.
|
95 |
+
if ( 0 !== $table_report['change'] ) {
|
96 |
+
$report['changes'][ $table ] = $table_report;
|
97 |
+
$report ['changes_count'] += $table_report['change'];
|
98 |
+
}
|
99 |
+
}
|
100 |
+
|
101 |
+
$this->max_execution->restore();
|
102 |
+
|
103 |
+
return $report;
|
104 |
+
}
|
105 |
+
|
106 |
+
/**
|
107 |
+
* Replace data values inside the table.
|
108 |
+
*
|
109 |
+
* @param string $search
|
110 |
+
* @param string $replace
|
111 |
+
* @param string $table
|
112 |
+
* @param null $csv
|
113 |
+
*
|
114 |
+
* @return array
|
115 |
+
* @throws \Throwable
|
116 |
+
*/
|
117 |
+
public function replace_values( $search = '', $replace = '', $table, $csv = null ) {
|
118 |
+
|
119 |
+
$table_report = [
|
120 |
+
'table_name' => $table,
|
121 |
+
'rows' => 0,
|
122 |
+
'change' => 0,
|
123 |
+
'changes' => [],
|
124 |
+
'updates' => 0,
|
125 |
+
'start' => microtime(),
|
126 |
+
'end' => microtime(),
|
127 |
+
'errors' => [],
|
128 |
+
];
|
129 |
+
|
130 |
+
// Check we have a search string, bail if not.
|
131 |
+
if ( empty( $search ) && empty( $csv ) ) {
|
132 |
+
$table_report['errors'][] = 'Search string is empty';
|
133 |
+
|
134 |
+
return $table_report;
|
135 |
+
}
|
136 |
+
|
137 |
+
// Grab table structure in order to determine which columns are used to store serialized values in it.
|
138 |
+
$table_structure = $this->dbm->get_table_structure( $table );
|
139 |
+
|
140 |
+
if ( ! $table_structure ) {
|
141 |
+
return $table_report;
|
142 |
+
}
|
143 |
+
|
144 |
+
$maybe_serialized = [];
|
145 |
+
foreach ( $table_structure as $struct ) {
|
146 |
+
// Longtext is used for meta_values as best practice in all of the automatic products.
|
147 |
+
// @codingStandardsIgnoreLine
|
148 |
+
if ( 0 === stripos( $struct->Type, 'longtext' ) ) {
|
149 |
+
// @codingStandardsIgnoreLine
|
150 |
+
$maybe_serialized[] = strtolower( $struct->Field );
|
151 |
+
}
|
152 |
+
}
|
153 |
+
|
154 |
+
// Split columns array in primary key string and columns array.
|
155 |
+
$columns = $this->dbm->get_columns( $table );
|
156 |
+
|
157 |
+
list( $primary_key, $columns ) = $columns;
|
158 |
+
|
159 |
+
if ( null === $primary_key ) {
|
160 |
+
array_push(
|
161 |
+
$table_report['errors'],
|
162 |
+
"The table \"{$table}\" has no primary key. Changes will have to be made manually.",
|
163 |
+
'results'
|
164 |
+
);
|
165 |
+
|
166 |
+
return $table_report;
|
167 |
+
}
|
168 |
+
|
169 |
+
$table_report['start'] = microtime();
|
170 |
+
|
171 |
+
// Count the number of rows we have in the table if large we'll split into blocks, This is a mod from Simon Wheatley
|
172 |
+
$row_count = $this->dbm->get_rows( $table );
|
173 |
+
|
174 |
+
$page_size = $this->page_size;
|
175 |
+
$pages = ceil( $row_count / $page_size );
|
176 |
+
|
177 |
+
// Prepare CSV data
|
178 |
+
if ( null !== $csv ) {
|
179 |
+
$csv_lines = explode( "\n", $csv );
|
180 |
+
$csv_head = str_getcsv( 'search,replace' );
|
181 |
+
foreach ( $csv_lines as $line ) {
|
182 |
+
$this->csv_data[] = array_combine( $csv_head, str_getcsv( $line ) );
|
183 |
+
}
|
184 |
+
}
|
185 |
+
|
186 |
+
for ( $page = 0; $page < $pages; $page ++ ) {
|
187 |
+
|
188 |
+
$start = $page * $page_size;
|
189 |
+
|
190 |
+
// Grab the content of the table
|
191 |
+
$data = $this->dbm->get_table_content( $table, $start, $page_size );
|
192 |
+
|
193 |
+
if ( ! $data ) {
|
194 |
+
$table_report['errors'][] = 'no data in table ' . $table;
|
195 |
+
}
|
196 |
+
|
197 |
+
foreach ( $data as $row ) {
|
198 |
+
++ $table_report['rows'];
|
199 |
+
|
200 |
+
$update_sql = [];
|
201 |
+
$where_sql = [];
|
202 |
+
$update = true;
|
203 |
+
|
204 |
+
foreach ( $columns as $column ) {
|
205 |
+
// Skip the GUID column per WordPress Codex.
|
206 |
+
if ( $column === 'guid' ) {
|
207 |
+
continue;
|
208 |
+
}
|
209 |
+
|
210 |
+
$data_to_fix = $row[ $column ];
|
211 |
+
|
212 |
+
if ( $column === $primary_key ) {
|
213 |
+
$where_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $data_to_fix ) . '"';
|
214 |
+
continue;
|
215 |
+
}
|
216 |
+
|
217 |
+
// Run a search replace on the data that'll respect the serialisation.
|
218 |
+
if ( is_serialized( $data_to_fix, false )
|
219 |
+
&& in_array( strtolower( $column ), $maybe_serialized, true )
|
220 |
+
) {
|
221 |
+
// Run a search replace on the data that'll respect the serialisation.
|
222 |
+
$edited_data = $this->recursive_unserialize_replace( $search, $replace, $data_to_fix );
|
223 |
+
} else {
|
224 |
+
$edited_data = str_replace( $search, $replace, $data_to_fix );
|
225 |
+
}
|
226 |
+
|
227 |
+
// Run a search replace by CSV parameters if CSV input present
|
228 |
+
if ( null !== $csv ) {
|
229 |
+
foreach ( $this->csv_data as $entry ) {
|
230 |
+
$edited_data = is_serialized( $edited_data, false ) ?
|
231 |
+
$this->recursive_unserialize_replace(
|
232 |
+
$entry['search'],
|
233 |
+
$entry['replace'],
|
234 |
+
$edited_data
|
235 |
+
) : str_replace( $entry['search'], $entry['replace'], $data_to_fix );
|
236 |
+
}
|
237 |
+
}
|
238 |
+
|
239 |
+
// Something was changed.
|
240 |
+
if ( $edited_data !== $data_to_fix ) {
|
241 |
+
++ $table_report['change'];
|
242 |
+
|
243 |
+
// log changes
|
244 |
+
// @todo : does it work with non UTF-8 encodings?
|
245 |
+
$table_report['changes'][] = [
|
246 |
+
'row' => $table_report['rows'],
|
247 |
+
'column' => $column,
|
248 |
+
'from' => $data_to_fix,
|
249 |
+
'to' => $edited_data,
|
250 |
+
];
|
251 |
+
|
252 |
+
$update_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $edited_data ) . '"';
|
253 |
+
$update = true;
|
254 |
+
}
|
255 |
+
}
|
256 |
+
|
257 |
+
// Determine what to do with updates.
|
258 |
+
if ( true === $this->dry_run ) {
|
259 |
+
// Don't do anything if a dry run.
|
260 |
+
continue;
|
261 |
+
}
|
262 |
+
|
263 |
+
if ( $update && ! empty( $where_sql ) && ! empty( $update_sql ) ) {
|
264 |
+
// If there are changes to make, run the query.
|
265 |
+
$result = $this->dbm->update( $table, $update_sql, $where_sql );
|
266 |
+
|
267 |
+
if ( ! $result ) {
|
268 |
+
$table_report['errors'][] = sprintf(
|
269 |
+
/* translators: $1 is the number of rows found in database */
|
270 |
+
esc_html__( 'Error updating row: %d.', 'search-and-replace' ),
|
271 |
+
$row
|
272 |
+
);
|
273 |
+
} else {
|
274 |
+
$table_report['updates'] ++;
|
275 |
+
}
|
276 |
+
}
|
277 |
+
}
|
278 |
+
}
|
279 |
+
|
280 |
+
$table_report['end'] = microtime( true );
|
281 |
+
|
282 |
+
$this->dbm->flush();
|
283 |
+
|
284 |
+
return $table_report;
|
285 |
+
|
286 |
+
}
|
287 |
+
|
288 |
+
/**
|
289 |
+
* Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
|
290 |
+
*
|
291 |
+
* @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
|
292 |
+
* @access public
|
293 |
+
*
|
294 |
+
* @param array|string $input The string to escape.
|
295 |
+
*
|
296 |
+
* @return string
|
297 |
+
*/
|
298 |
+
public function mysql_escape_mimic( $input ) {
|
299 |
+
|
300 |
+
if ( is_array( $input ) ) {
|
301 |
+
return array_map( __METHOD__, $input );
|
302 |
+
}
|
303 |
+
if ( ! empty( $input ) && is_string( $input ) ) {
|
304 |
+
return str_replace(
|
305 |
+
[ '\\', "\0", "\n", "\r", "'", '"', "\x1a" ],
|
306 |
+
[ '\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z' ],
|
307 |
+
$input
|
308 |
+
);
|
309 |
+
}
|
310 |
+
|
311 |
+
return $input;
|
312 |
+
}
|
313 |
+
|
314 |
+
/**
|
315 |
+
* Recursive unserialize replace
|
316 |
+
*
|
317 |
+
* Take a serialised array and unserialize it replacing elements as needed and
|
318 |
+
* unserializing any subordinate arrays and performing the replace on those too.
|
319 |
+
*
|
320 |
+
* Be aware, the method due to his recursive characteristic cannot prevent execution in case the
|
321 |
+
* data passed to the function isn't a serialized value at the first time.
|
322 |
+
*
|
323 |
+
* It's up to you to be sure the value is serialized before call the method.
|
324 |
+
*
|
325 |
+
* @param string $from String we're looking to replace.
|
326 |
+
* @param string $to What we want it to be replaced with.
|
327 |
+
* @param array|string|object $data Used to pass any subordinate arrays back to in.
|
328 |
+
* @param bool $serialised Does the array passed via $data need serialising. Default to true.
|
329 |
+
*
|
330 |
+
* @throws \Throwable Whatever exception is thrown if WP_DEBUG is true.
|
331 |
+
*
|
332 |
+
* @return array The original array with all elements replaced as needed.
|
333 |
+
*/
|
334 |
+
public function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialised = true ) {
|
335 |
+
|
336 |
+
// Some unserialized data cannot be re-serialised eg. SimpleXMLElements.
|
337 |
+
try {
|
338 |
+
$unserialized = is_serialized( $data, false ) ? maybe_unserialize( $data ) : false;
|
339 |
+
|
340 |
+
if ( $unserialized !== false && ! is_serialized_string( $data ) ) {
|
341 |
+
$data = $this->recursive_unserialize_replace( $from, $to, $unserialized, false );
|
342 |
+
} elseif ( is_array( $data ) ) {
|
343 |
+
$_tmp = [];
|
344 |
+
foreach ( (array) $data as $key => $value ) {
|
345 |
+
$_tmp[ $key ] = $this->recursive_unserialize_replace( $from, $to, $value, false );
|
346 |
+
}
|
347 |
+
|
348 |
+
$data = $_tmp;
|
349 |
+
|
350 |
+
unset( $_tmp );
|
351 |
+
} elseif ( is_object( $data ) ) {
|
352 |
+
$_tmp = $data;
|
353 |
+
$props = get_object_vars( $data );
|
354 |
+
foreach ( $props as $key => $value ) {
|
355 |
+
$_tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false );
|
356 |
+
}
|
357 |
+
|
358 |
+
$data = $_tmp;
|
359 |
+
|
360 |
+
unset( $_tmp );
|
361 |
+
} else {
|
362 |
+
// Don't process data that isn't a string.
|
363 |
+
// In this case, just return it because we haven't coverage for this kind of value.
|
364 |
+
if ( ! is_string( $data ) ) {
|
365 |
+
return $data;
|
366 |
+
}
|
367 |
+
|
368 |
+
$marker = false;
|
369 |
+
|
370 |
+
if ( is_serialized_string( $data ) ) {
|
371 |
+
// @codingStandardsIgnoreLine
|
372 |
+
$data = maybe_unserialize( $data );
|
373 |
+
$marker = true;
|
374 |
+
}
|
375 |
+
|
376 |
+
$tmp_data = $data;
|
377 |
+
$data = str_replace( $from, $to, $data );
|
378 |
+
|
379 |
+
// Do not allow to return valid serialized data,
|
380 |
+
// If after replacement data is_serialized then add one | to the replacement.
|
381 |
+
if ( is_serialized( $data, false ) ) {
|
382 |
+
$data = str_replace( $from, '|' . $to, $tmp_data );
|
383 |
+
}
|
384 |
+
|
385 |
+
if ( $marker ) {
|
386 |
+
$data = maybe_serialize( $data );
|
387 |
+
}
|
388 |
+
}
|
389 |
+
|
390 |
+
if ( $serialised ) {
|
391 |
+
// @codingStandardsIgnoreLine
|
392 |
+
$data = serialize( $data );
|
393 |
+
}
|
394 |
+
} catch ( Exception $throwable ) {
|
395 |
+
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
396 |
+
throw $throwable;
|
397 |
+
}
|
398 |
+
|
399 |
+
do_action( 'inpsyde.search_and_replace.error', $throwable );
|
400 |
+
}
|
401 |
+
|
402 |
+
return $data;
|
403 |
+
}
|
404 |
+
|
405 |
+
/**
|
406 |
+
* Returns true, if dry run, false if not
|
407 |
+
*
|
408 |
+
* @return bool
|
409 |
+
*/
|
410 |
+
public function get_dry_run() {
|
411 |
+
|
412 |
+
return $this->dry_run;
|
413 |
+
}
|
414 |
+
|
415 |
+
/**
|
416 |
+
* Sets the dry run option.
|
417 |
+
*
|
418 |
+
* @param bool $state : TRUE for dry run, FALSE for writing changes to DB.
|
419 |
+
*
|
420 |
+
* @return bool
|
421 |
+
*/
|
422 |
+
public function set_dry_run( $state ) {
|
423 |
+
|
424 |
+
if ( is_bool( $state ) ) {
|
425 |
+
|
426 |
+
$this->dry_run = $state;
|
427 |
+
}
|
428 |
+
|
429 |
+
return $state;
|
430 |
+
}
|
431 |
+
}
|
inc/FileDownloader.php
CHANGED
@@ -1,374 +1,374 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace Inpsyde\SearchReplace;
|
4 |
-
|
5 |
-
use Inpsyde\SearchReplace\Database\Exporter;
|
6 |
-
use Inpsyde\SearchReplace\Service\MaxExecutionTime;
|
7 |
-
|
8 |
-
/**
|
9 |
-
* Class FileDownloader
|
10 |
-
*
|
11 |
-
* @package Inpsyde\SearchReplace
|
12 |
-
*/
|
13 |
-
class FileDownloader {
|
14 |
-
|
15 |
-
/**
|
16 |
-
* @var string
|
17 |
-
*/
|
18 |
-
private $nonce_action = 'download_sql';
|
19 |
-
|
20 |
-
/**
|
21 |
-
* @var string
|
22 |
-
*/
|
23 |
-
private $nonce_name = 'insr_nonce_download';
|
24 |
-
|
25 |
-
/**
|
26 |
-
* @var Exporter
|
27 |
-
*/
|
28 |
-
private $dbe;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* @var MaxExecutionTime
|
32 |
-
*/
|
33 |
-
private $max_execution;
|
34 |
-
|
35 |
-
/**
|
36 |
-
* Admin constructor.
|
37 |
-
*
|
38 |
-
* @param Exporter $dbe
|
39 |
-
* @param MaxExecutionTime $max_execution
|
40 |
-
*/
|
41 |
-
public function __construct( Exporter $dbe, MaxExecutionTime $max_execution ) {
|
42 |
-
|
43 |
-
$this->dbe = $dbe;
|
44 |
-
$this->max_execution = $max_execution;
|
45 |
-
}
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Renders to download modal.
|
49 |
-
*
|
50 |
-
* @param array $report
|
51 |
-
*/
|
52 |
-
public function show_modal( $report ) {
|
53 |
-
|
54 |
-
// Set compress status.
|
55 |
-
// @codingStandardsIgnoreLine
|
56 |
-
$compress = ( isset( $_POST['compress'] ) && 'on' === $_POST['compress'] );
|
57 |
-
|
58 |
-
if ( array_key_exists( 'changes', $report ) && ! empty( $report['changes'] ) ) :
|
59 |
-
?>
|
60 |
-
<div class="updated notice is-dismissible">
|
61 |
-
<?php
|
62 |
-
// Show changes if there are any.
|
63 |
-
if ( count( $report['changes'] ) > 0 ) {
|
64 |
-
$this->show_changes( $report );
|
65 |
-
}
|
66 |
-
|
67 |
-
// If no changes found report that.
|
68 |
-
if ( 0 === count( $report ['changes'] ) ) {
|
69 |
-
echo '<p>' . esc_html__( 'Search pattern not found.', 'search-and-replace' ) . '</p>';
|
70 |
-
}
|
71 |
-
?>
|
72 |
-
</div>
|
73 |
-
<?php
|
74 |
-
endif;
|
75 |
-
?>
|
76 |
-
|
77 |
-
<div class="updated notice is-dismissible insr_sql_button_wrap">
|
78 |
-
<p><?php esc_html_e( 'Your SQL file was created!', 'search-and-replace' ); ?> </p>
|
79 |
-
<form action method="post">
|
80 |
-
<?php wp_nonce_field( $this->nonce_action, $this->nonce_name ); ?>
|
81 |
-
<input type="hidden" name="action" value="download_file"/>
|
82 |
-
<input type="hidden" name="sql_file" value="<?php echo esc_attr( $report['filename'] ); ?>">
|
83 |
-
<input type="hidden" name="compress" value="<?php echo esc_attr( $compress ); ?>">
|
84 |
-
<input id="insr_submit" type="submit" value="<?php esc_attr_e(
|
85 |
-
'Download SQL File', 'search-and-replace'
|
86 |
-
) ?>" class="button"/>
|
87 |
-
</form>
|
88 |
-
</div>
|
89 |
-
<?php
|
90 |
-
}
|
91 |
-
|
92 |
-
/**
|
93 |
-
* Displays the changes made to the db
|
94 |
-
* echoes the changes in formatted html.
|
95 |
-
*
|
96 |
-
* @param array $report WP-Error Object if Errors
|
97 |
-
*
|
98 |
-
* 'tables' : Number of tables processed
|
99 |
-
* 'changes_count' : Number of changes made
|
100 |
-
* 'changes' : Array with at least these elements:
|
101 |
-
* 'table_name'=> $[name of current table],
|
102 |
-
* 'changes' => array('row' => [row that has been changed ],
|
103 |
-
* 'column' => [column that has been changed],
|
104 |
-
* 'from' => ( old value ),
|
105 |
-
* 'to' => ( $new value ),
|
106 |
-
* .
|
107 |
-
*/
|
108 |
-
public function show_changes( $report ) {
|
109 |
-
|
110 |
-
// Get search & replace values in order to highlight them in the results.
|
111 |
-
// @codingStandardsIgnoreStart
|
112 |
-
$search = isset( $_POST['search'] ) ?
|
113 |
-
esc_html( filter_var( $_POST ['search'], FILTER_SANITIZE_STRING ) ) :
|
114 |
-
'';
|
115 |
-
$replace = isset( $_POST['replace'] ) ?
|
116 |
-
esc_html( filter_var( $_POST ['replace'], FILTER_SANITIZE_STRING ) ) :
|
117 |
-
'';
|
118 |
-
// @codingStandardsIgnoreEnd
|
119 |
-
|
120 |
-
$search_highlight = '<span class="search-replace-search-value">' . $search . '</span>';
|
121 |
-
$replace_highlight = '<span class ="search-replace-replace-value">' . $replace . '</span>';
|
122 |
-
$delimiter = [ ' ...', '...<br>' ];
|
123 |
-
|
124 |
-
$this->show_message_by_report( $report );
|
125 |
-
|
126 |
-
?>
|
127 |
-
<p><a href="#" id="changes-modal-button"><?php esc_html_e( 'View details', 'search-and-replace' ); ?></a></p>
|
128 |
-
<div id="changes-modal-background" class="search-replace-modal-background" style="display: none;"></div>
|
129 |
-
<div id="changes-modal" class="search-replace-modal " style="display: none;">
|
130 |
-
<div class="search-replace-modal-header">
|
131 |
-
<button type="button" id="changes-modal-close" class="search-replace-modal-close-button"></button>
|
132 |
-
</div>
|
133 |
-
<div class="search-replace-changes-modal-content">
|
134 |
-
<?php
|
135 |
-
foreach ( $report['changes'] as $table_report ) :
|
136 |
-
$changes = $table_report['changes'];
|
137 |
-
$changes_made = count( $changes );
|
138 |
-
|
139 |
-
if ( $changes_made < 1 ) {
|
140 |
-
continue;
|
141 |
-
}
|
142 |
-
|
143 |
-
$table = $table_report['table_name'];
|
144 |
-
?>
|
145 |
-
<h2 class="search-replace-modal-table-headline">
|
146 |
-
<strong><?php esc_html_e( 'Table:', 'search-and-replace' ); ?></strong>
|
147 |
-
<?php echo esc_html( $table ); ?>
|
148 |
-
|
149 |
-
<strong><?php esc_html_e( 'Columns Changes:', 'search-and-replace' ); ?></strong>
|
150 |
-
<?php echo esc_html( $changes_made ); ?>
|
151 |
-
</h2>
|
152 |
-
|
153 |
-
<table class="search-replace-modal-table">
|
154 |
-
|
155 |
-
<thead>
|
156 |
-
<tr>
|
157 |
-
<th class="search-replace-row search-replace-narrow">
|
158 |
-
<?php esc_html_e( 'Row', 'search-and-replace' ); ?>
|
159 |
-
</th>
|
160 |
-
<th class="search-replace-column">
|
161 |
-
<?php esc_html_e( 'Column', 'search-and-replace' ); ?>
|
162 |
-
</th>
|
163 |
-
<th class="search-replace-old-value">
|
164 |
-
<?php esc_html_e( 'Old value', 'search-and-replace' ); ?>
|
165 |
-
</th>
|
166 |
-
<th class="search-replace-new-value">
|
167 |
-
<?php esc_html_e( 'New value', 'search-and-replace' ); ?>
|
168 |
-
</th>
|
169 |
-
</tr>
|
170 |
-
</thead>
|
171 |
-
|
172 |
-
<tbody>
|
173 |
-
<?php
|
174 |
-
foreach ( $changes as $change ) :
|
175 |
-
// Trim results and wrap with highlight class.
|
176 |
-
$old_value = esc_html( $change ['from'] );
|
177 |
-
$old_value = $this->trim_search_results( $search, $old_value, $delimiter );
|
178 |
-
$old_value = str_replace( $search, $search_highlight, $old_value );
|
179 |
-
|
180 |
-
$new_value = esc_html( $change['to'] );
|
181 |
-
$new_value = $this->trim_search_results( $replace, $new_value, $delimiter );
|
182 |
-
$new_value = str_replace( $replace, $replace_highlight, $new_value );
|
183 |
-
|
184 |
-
if ( $old_value && $new_value ) :
|
185 |
-
?>
|
186 |
-
<tr>
|
187 |
-
<td class="search-replace-row search-replace-narrow">
|
188 |
-
<?php echo esc_html( $change ['row'] ); ?>
|
189 |
-
</td>
|
190 |
-
<td class="search-replace-column">
|
191 |
-
<?php echo esc_html( $change ['column'] ); ?>
|
192 |
-
</td>
|
193 |
-
<td class="search-replace-old-value">
|
194 |
-
<?php echo wp_kses( $old_value, [ 'span' => [ 'class' => [] ] ] ); ?>
|
195 |
-
</td>
|
196 |
-
<td class="search-replace-new-value">
|
197 |
-
<?php echo wp_kses( $new_value, [ 'span' => [ 'class' => [] ] ] ); ?>
|
198 |
-
</td>
|
199 |
-
</tr>
|
200 |
-
<?php
|
201 |
-
endif;
|
202 |
-
endforeach;
|
203 |
-
?>
|
204 |
-
</tbody>
|
205 |
-
|
206 |
-
</table>
|
207 |
-
|
208 |
-
<?php endforeach; ?>
|
209 |
-
|
210 |
-
</div>
|
211 |
-
</div>
|
212 |
-
<?php
|
213 |
-
}
|
214 |
-
|
215 |
-
/**
|
216 |
-
* Show Message by Report
|
217 |
-
*
|
218 |
-
* @param array $report The list of all the changes made.
|
219 |
-
*
|
220 |
-
* @return void
|
221 |
-
*/
|
222 |
-
private function show_message_by_report( $report ) {
|
223 |
-
|
224 |
-
$msg = sprintf(
|
225 |
-
// translators: %s is the count of tables.
|
226 |
-
_n(
|
227 |
-
'%s table was processed. ',
|
228 |
-
'%s tables were processed. ',
|
229 |
-
$report['tables'],
|
230 |
-
'search-and-replace'
|
231 |
-
),
|
232 |
-
(int) $report['tables']
|
233 |
-
);
|
234 |
-
|
235 |
-
$msg .= sprintf(
|
236 |
-
// translators: %s is the count of selected cells after search in tables.
|
237 |
-
_n(
|
238 |
-
'%s cell needs to be updated.
|
239 |
-
'%s cells need to be updated.',
|
240 |
-
$report['changes_count'],
|
241 |
-
'search-and-replace'
|
242 |
-
),
|
243 |
-
(int) $report['changes_count']
|
244 |
-
);
|
245 |
-
|
246 |
-
echo '<p>' . esc_html( $msg ) . '</p>';
|
247 |
-
}
|
248 |
-
|
249 |
-
/**
|
250 |
-
* Trims a given string to 50 chars before and after the search string, if the string is longer than 199 chars.
|
251 |
-
*
|
252 |
-
* @param string $needle
|
253 |
-
* @param string $haystack
|
254 |
-
* @param array $delimiter $delimiter[0]=start delimiter, $delimiter[1] = end delimiter.
|
255 |
-
*
|
256 |
-
* @return string The trimmed $haystack
|
257 |
-
*/
|
258 |
-
public function trim_search_results( $needle, $haystack, $delimiter ) {
|
259 |
-
|
260 |
-
// Ff result has <100 characters we return the whole string.
|
261 |
-
if ( strlen( $haystack ) < 100 ) {
|
262 |
-
return $haystack;
|
263 |
-
}
|
264 |
-
$trimmed_results = null;
|
265 |
-
// Get all occurrences of $needle with up to 50 chars front & back.
|
266 |
-
$matches = preg_match_all( '@.{0,50}' . $needle . '.{0,50}@', $haystack, $trimmed_results );
|
267 |
-
$return_value = '';
|
268 |
-
|
269 |
-
// Don't need to perform any action if no matches.
|
270 |
-
if ( ! $matches ) {
|
271 |
-
return $return_value;
|
272 |
-
}
|
273 |
-
|
274 |
-
for ( $i = 0; $i < $matches; $i ++ ) {
|
275 |
-
// Reset delimiter, might have been changed.
|
276 |
-
$local_delimiter = $delimiter;
|
277 |
-
|
278 |
-
// Check if the first trimmed result is the beginning of $haystack. if so remove leading delimiter.
|
279 |
-
if ( $i === 0 ) {
|
280 |
-
$pos = strpos( $haystack, $trimmed_results[0][ $i ] );
|
281 |
-
if ( $pos === 0 ) {
|
282 |
-
$local_delimiter[0] = '';
|
283 |
-
}
|
284 |
-
}
|
285 |
-
|
286 |
-
// Check if the last trimmed result is the end of $haystack. if so, remove trailing delimiter.
|
287 |
-
$last_index = $matches - 1;
|
288 |
-
|
289 |
-
if ( $i === $last_index ) {
|
290 |
-
$trimmed_result_length = strlen( $trimmed_results[0][ $i ] );
|
291 |
-
$substring = substr( $haystack, - $trimmed_result_length );
|
292 |
-
|
293 |
-
if ( $substring === $trimmed_results[0][ $i ] ) {
|
294 |
-
$local_delimiter[1] = '';
|
295 |
-
}
|
296 |
-
}
|
297 |
-
$return_value .= $local_delimiter[0] . $trimmed_results[0][ $i ] . $local_delimiter[1];
|
298 |
-
}
|
299 |
-
|
300 |
-
return $return_value;
|
301 |
-
}
|
302 |
-
|
303 |
-
/**
|
304 |
-
* Calls the file delivery in Class DatabaseExporter.
|
305 |
-
*
|
306 |
-
* @wp-hook init
|
307 |
-
*
|
308 |
-
* @return bool
|
309 |
-
*/
|
310 |
-
public function deliver_backup_file() {
|
311 |
-
|
312 |
-
// Retrieve the nonce value.
|
313 |
-
// @codingStandardsIgnoreStart
|
314 |
-
$nonce = isset( $_POST[ $this->nonce_name ] ) ?
|
315 |
-
filter_var( $_POST[ $this->nonce_name ], FILTER_SANITIZE_STRING )
|
316 |
-
: '';
|
317 |
-
// @codingStandardsIgnoreEnd
|
318 |
-
|
319 |
-
// If nonce has not been send, just return nothing else to do here.
|
320 |
-
// The method may be hooked to a wp action, so it's executed on every page request.
|
321 |
-
if ( ! $nonce ) {
|
322 |
-
return false;
|
323 |
-
}
|
324 |
-
|
325 |
-
// Die in case the nonce has been passed but not a valid one.
|
326 |
-
// @codingStandardsIgnoreLine
|
327 |
-
if ( ! wp_verify_nonce( $_POST[ $this->nonce_name ], $this->nonce_action ) ) {
|
328 |
-
wp_die( 'Cheating Uh?' );
|
329 |
-
}
|
330 |
-
|
331 |
-
$this->max_execution->set();
|
332 |
-
|
333 |
-
// Get the action to perform.
|
334 |
-
// @codingStandardsIgnoreLine
|
335 |
-
$action = isset( $_POST['action'] ) ? filter_var( $_POST['action'], FILTER_SANITIZE_STRING ) : '';
|
336 |
-
|
337 |
-
if ( 'download_file' !== $action ) {
|
338 |
-
return false;
|
339 |
-
}
|
340 |
-
|
341 |
-
$sql_file = '';
|
342 |
-
$compress = false;
|
343 |
-
|
344 |
-
// @codingStandardsIgnoreLine
|
345 |
-
if ( isset( $_POST['sql_file'] ) ) {
|
346 |
-
// @codingStandardsIgnoreLine
|
347 |
-
$sql_file = sanitize_file_name( $_POST['sql_file'] );
|
348 |
-
}
|
349 |
-
|
350 |
-
if ( ! $sql_file ) {
|
351 |
-
wp_die( esc_html__( 'The file you are looking for doesn\'t exists.', 'search-and-replace' ) );
|
352 |
-
}
|
353 |
-
|
354 |
-
// If file name contains path or does not end with '.sql' exit.
|
355 |
-
// @ToDo create a function to prevent traversal path.
|
356 |
-
$ext = strrchr( $sql_file, '.' );
|
357 |
-
if ( false !== strpos( $sql_file, '/' ) || '.sql' !== $ext ) {
|
358 |
-
wp_die( 'Cheating Uh?' );
|
359 |
-
}
|
360 |
-
|
361 |
-
// @codingStandardsIgnoreLine
|
362 |
-
if ( isset( $_POST['compress'] ) ) {
|
363 |
-
// @codingStandardsIgnoreLine
|
364 |
-
$compress = (bool) filter_var( $_POST['compress'], FILTER_VALIDATE_BOOLEAN );
|
365 |
-
}
|
366 |
-
|
367 |
-
// Download the file.
|
368 |
-
$this->dbe->deliver_backup( $sql_file, $compress );
|
369 |
-
|
370 |
-
$this->max_execution->restore();
|
371 |
-
|
372 |
-
return true;
|
373 |
-
}
|
374 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Inpsyde\SearchReplace;
|
4 |
+
|
5 |
+
use Inpsyde\SearchReplace\Database\Exporter;
|
6 |
+
use Inpsyde\SearchReplace\Service\MaxExecutionTime;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class FileDownloader
|
10 |
+
*
|
11 |
+
* @package Inpsyde\SearchReplace
|
12 |
+
*/
|
13 |
+
class FileDownloader {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @var string
|
17 |
+
*/
|
18 |
+
private $nonce_action = 'download_sql';
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @var string
|
22 |
+
*/
|
23 |
+
private $nonce_name = 'insr_nonce_download';
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @var Exporter
|
27 |
+
*/
|
28 |
+
private $dbe;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @var MaxExecutionTime
|
32 |
+
*/
|
33 |
+
private $max_execution;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Admin constructor.
|
37 |
+
*
|
38 |
+
* @param Exporter $dbe
|
39 |
+
* @param MaxExecutionTime $max_execution
|
40 |
+
*/
|
41 |
+
public function __construct( Exporter $dbe, MaxExecutionTime $max_execution ) {
|
42 |
+
|
43 |
+
$this->dbe = $dbe;
|
44 |
+
$this->max_execution = $max_execution;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Renders to download modal.
|
49 |
+
*
|
50 |
+
* @param array $report
|
51 |
+
*/
|
52 |
+
public function show_modal( $report ) {
|
53 |
+
|
54 |
+
// Set compress status.
|
55 |
+
// @codingStandardsIgnoreLine
|
56 |
+
$compress = ( isset( $_POST['compress'] ) && 'on' === $_POST['compress'] );
|
57 |
+
|
58 |
+
if ( array_key_exists( 'changes', $report ) && ! empty( $report['changes'] ) ) :
|
59 |
+
?>
|
60 |
+
<div class="updated notice is-dismissible">
|
61 |
+
<?php
|
62 |
+
// Show changes if there are any.
|
63 |
+
if ( count( $report['changes'] ) > 0 ) {
|
64 |
+
$this->show_changes( $report );
|
65 |
+
}
|
66 |
+
|
67 |
+
// If no changes found report that.
|
68 |
+
if ( 0 === count( $report ['changes'] ) ) {
|
69 |
+
echo '<p>' . esc_html__( 'Search pattern not found.', 'search-and-replace' ) . '</p>';
|
70 |
+
}
|
71 |
+
?>
|
72 |
+
</div>
|
73 |
+
<?php
|
74 |
+
endif;
|
75 |
+
?>
|
76 |
+
|
77 |
+
<div class="updated notice is-dismissible insr_sql_button_wrap">
|
78 |
+
<p><?php esc_html_e( 'Your SQL file was created!', 'search-and-replace' ); ?> </p>
|
79 |
+
<form action method="post">
|
80 |
+
<?php wp_nonce_field( $this->nonce_action, $this->nonce_name ); ?>
|
81 |
+
<input type="hidden" name="action" value="download_file"/>
|
82 |
+
<input type="hidden" name="sql_file" value="<?php echo esc_attr( $report['filename'] ); ?>">
|
83 |
+
<input type="hidden" name="compress" value="<?php echo esc_attr( $compress ); ?>">
|
84 |
+
<input id="insr_submit" type="submit" value="<?php esc_attr_e(
|
85 |
+
'Download SQL File', 'search-and-replace'
|
86 |
+
) ?>" class="button"/>
|
87 |
+
</form>
|
88 |
+
</div>
|
89 |
+
<?php
|
90 |
+
}
|
91 |
+
|
92 |
+
/**
|
93 |
+
* Displays the changes made to the db
|
94 |
+
* echoes the changes in formatted html.
|
95 |
+
*
|
96 |
+
* @param array $report WP-Error Object if Errors
|
97 |
+
*
|
98 |
+
* 'tables' : Number of tables processed
|
99 |
+
* 'changes_count' : Number of changes made
|
100 |
+
* 'changes' : Array with at least these elements:
|
101 |
+
* 'table_name'=> $[name of current table],
|
102 |
+
* 'changes' => array('row' => [row that has been changed ],
|
103 |
+
* 'column' => [column that has been changed],
|
104 |
+
* 'from' => ( old value ),
|
105 |
+
* 'to' => ( $new value ),
|
106 |
+
* .
|
107 |
+
*/
|
108 |
+
public function show_changes( $report ) {
|
109 |
+
|
110 |
+
// Get search & replace values in order to highlight them in the results.
|
111 |
+
// @codingStandardsIgnoreStart
|
112 |
+
$search = isset( $_POST['search'] ) ?
|
113 |
+
esc_html( filter_var( $_POST ['search'], FILTER_SANITIZE_STRING ) ) :
|
114 |
+
'';
|
115 |
+
$replace = isset( $_POST['replace'] ) ?
|
116 |
+
esc_html( filter_var( $_POST ['replace'], FILTER_SANITIZE_STRING ) ) :
|
117 |
+
'';
|
118 |
+
// @codingStandardsIgnoreEnd
|
119 |
+
|
120 |
+
$search_highlight = '<span class="search-replace-search-value">' . $search . '</span>';
|
121 |
+
$replace_highlight = '<span class ="search-replace-replace-value">' . $replace . '</span>';
|
122 |
+
$delimiter = [ ' ...', '...<br>' ];
|
123 |
+
|
124 |
+
$this->show_message_by_report( $report );
|
125 |
+
|
126 |
+
?>
|
127 |
+
<p><a href="#" id="changes-modal-button"><?php esc_html_e( 'View details', 'search-and-replace' ); ?></a></p>
|
128 |
+
<div id="changes-modal-background" class="search-replace-modal-background" style="display: none;"></div>
|
129 |
+
<div id="changes-modal" class="search-replace-modal " style="display: none;">
|
130 |
+
<div class="search-replace-modal-header">
|
131 |
+
<button type="button" id="changes-modal-close" class="search-replace-modal-close-button"></button>
|
132 |
+
</div>
|
133 |
+
<div class="search-replace-changes-modal-content">
|
134 |
+
<?php
|
135 |
+
foreach ( $report['changes'] as $table_report ) :
|
136 |
+
$changes = $table_report['changes'];
|
137 |
+
$changes_made = count( $changes );
|
138 |
+
|
139 |
+
if ( $changes_made < 1 ) {
|
140 |
+
continue;
|
141 |
+
}
|
142 |
+
|
143 |
+
$table = $table_report['table_name'];
|
144 |
+
?>
|
145 |
+
<h2 class="search-replace-modal-table-headline">
|
146 |
+
<strong><?php esc_html_e( 'Table:', 'search-and-replace' ); ?></strong>
|
147 |
+
<?php echo esc_html( $table ); ?>
|
148 |
+
|
149 |
+
<strong><?php esc_html_e( 'Columns Changes:', 'search-and-replace' ); ?></strong>
|
150 |
+
<?php echo esc_html( $changes_made ); ?>
|
151 |
+
</h2>
|
152 |
+
|
153 |
+
<table class="search-replace-modal-table">
|
154 |
+
|
155 |
+
<thead>
|
156 |
+
<tr>
|
157 |
+
<th class="search-replace-row search-replace-narrow">
|
158 |
+
<?php esc_html_e( 'Row', 'search-and-replace' ); ?>
|
159 |
+
</th>
|
160 |
+
<th class="search-replace-column">
|
161 |
+
<?php esc_html_e( 'Column', 'search-and-replace' ); ?>
|
162 |
+
</th>
|
163 |
+
<th class="search-replace-old-value">
|
164 |
+
<?php esc_html_e( 'Old value', 'search-and-replace' ); ?>
|
165 |
+
</th>
|
166 |
+
<th class="search-replace-new-value">
|
167 |
+
<?php esc_html_e( 'New value', 'search-and-replace' ); ?>
|
168 |
+
</th>
|
169 |
+
</tr>
|
170 |
+
</thead>
|
171 |
+
|
172 |
+
<tbody>
|
173 |
+
<?php
|
174 |
+
foreach ( $changes as $change ) :
|
175 |
+
// Trim results and wrap with highlight class.
|
176 |
+
$old_value = esc_html( $change ['from'] );
|
177 |
+
$old_value = $this->trim_search_results( $search, $old_value, $delimiter );
|
178 |
+
$old_value = str_replace( $search, $search_highlight, $old_value );
|
179 |
+
|
180 |
+
$new_value = esc_html( $change['to'] );
|
181 |
+
$new_value = $this->trim_search_results( $replace, $new_value, $delimiter );
|
182 |
+
$new_value = str_replace( $replace, $replace_highlight, $new_value );
|
183 |
+
|
184 |
+
if ( $old_value && $new_value ) :
|
185 |
+
?>
|
186 |
+
<tr>
|
187 |
+
<td class="search-replace-row search-replace-narrow">
|
188 |
+
<?php echo esc_html( $change ['row'] ); ?>
|
189 |
+
</td>
|
190 |
+
<td class="search-replace-column">
|
191 |
+
<?php echo esc_html( $change ['column'] ); ?>
|
192 |
+
</td>
|
193 |
+
<td class="search-replace-old-value">
|
194 |
+
<?php echo wp_kses( $old_value, [ 'span' => [ 'class' => [] ] ] ); ?>
|
195 |
+
</td>
|
196 |
+
<td class="search-replace-new-value">
|
197 |
+
<?php echo wp_kses( $new_value, [ 'span' => [ 'class' => [] ] ] ); ?>
|
198 |
+
</td>
|
199 |
+
</tr>
|
200 |
+
<?php
|
201 |
+
endif;
|
202 |
+
endforeach;
|
203 |
+
?>
|
204 |
+
</tbody>
|
205 |
+
|
206 |
+
</table>
|
207 |
+
|
208 |
+
<?php endforeach; ?>
|
209 |
+
|
210 |
+
</div>
|
211 |
+
</div>
|
212 |
+
<?php
|
213 |
+
}
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Show Message by Report
|
217 |
+
*
|
218 |
+
* @param array $report The list of all the changes made.
|
219 |
+
*
|
220 |
+
* @return void
|
221 |
+
*/
|
222 |
+
private function show_message_by_report( $report ) {
|
223 |
+
|
224 |
+
$msg = sprintf(
|
225 |
+
// translators: %s is the count of tables.
|
226 |
+
_n(
|
227 |
+
'%s table was processed. ',
|
228 |
+
'%s tables were processed. ',
|
229 |
+
$report['tables'],
|
230 |
+
'search-and-replace'
|
231 |
+
),
|
232 |
+
(int) $report['tables']
|
233 |
+
);
|
234 |
+
|
235 |
+
$msg .= sprintf(
|
236 |
+
// translators: %s is the count of selected cells after search in tables.
|
237 |
+
_n(
|
238 |
+
'%s cell needs to be updated.',
|
239 |
+
'%s cells need to be updated.',
|
240 |
+
$report['changes_count'],
|
241 |
+
'search-and-replace'
|
242 |
+
),
|
243 |
+
(int) $report['changes_count']
|
244 |
+
);
|
245 |
+
|
246 |
+
echo '<p>' . esc_html( $msg ) . '</p>';
|
247 |
+
}
|
248 |
+
|
249 |
+
/**
|
250 |
+
* Trims a given string to 50 chars before and after the search string, if the string is longer than 199 chars.
|
251 |
+
*
|
252 |
+
* @param string $needle
|
253 |
+
* @param string $haystack
|
254 |
+
* @param array $delimiter $delimiter[0]=start delimiter, $delimiter[1] = end delimiter.
|
255 |
+
*
|
256 |
+
* @return string The trimmed $haystack
|
257 |
+
*/
|
258 |
+
public function trim_search_results( $needle, $haystack, $delimiter ) {
|
259 |
+
|
260 |
+
// Ff result has <100 characters we return the whole string.
|
261 |
+
if ( strlen( $haystack ) < 100 ) {
|
262 |
+
return $haystack;
|
263 |
+
}
|
264 |
+
$trimmed_results = null;
|
265 |
+
// Get all occurrences of $needle with up to 50 chars front & back.
|
266 |
+
$matches = preg_match_all( '@.{0,50}' . $needle . '.{0,50}@', $haystack, $trimmed_results );
|
267 |
+
$return_value = '';
|
268 |
+
|
269 |
+
// Don't need to perform any action if no matches.
|
270 |
+
if ( ! $matches ) {
|
271 |
+
return $return_value;
|
272 |
+
}
|
273 |
+
|
274 |
+
for ( $i = 0; $i < $matches; $i ++ ) {
|
275 |
+
// Reset delimiter, might have been changed.
|
276 |
+
$local_delimiter = $delimiter;
|
277 |
+
|
278 |
+
// Check if the first trimmed result is the beginning of $haystack. if so remove leading delimiter.
|
279 |
+
if ( $i === 0 ) {
|
280 |
+
$pos = strpos( $haystack, $trimmed_results[0][ $i ] );
|
281 |
+
if ( $pos === 0 ) {
|
282 |
+
$local_delimiter[0] = '';
|
283 |
+
}
|
284 |
+
}
|
285 |
+
|
286 |
+
// Check if the last trimmed result is the end of $haystack. if so, remove trailing delimiter.
|
287 |
+
$last_index = $matches - 1;
|
288 |
+
|
289 |
+
if ( $i === $last_index ) {
|
290 |
+
$trimmed_result_length = strlen( $trimmed_results[0][ $i ] );
|
291 |
+
$substring = substr( $haystack, - $trimmed_result_length );
|
292 |
+
|
293 |
+
if ( $substring === $trimmed_results[0][ $i ] ) {
|
294 |
+
$local_delimiter[1] = '';
|
295 |
+
}
|
296 |
+
}
|
297 |
+
$return_value .= $local_delimiter[0] . $trimmed_results[0][ $i ] . $local_delimiter[1];
|
298 |
+
}
|
299 |
+
|
300 |
+
return $return_value;
|
301 |
+
}
|
302 |
+
|
303 |
+
/**
|
304 |
+
* Calls the file delivery in Class DatabaseExporter.
|
305 |
+
*
|
306 |
+
* @wp-hook init
|
307 |
+
*
|
308 |
+
* @return bool
|
309 |
+
*/
|
310 |
+
public function deliver_backup_file() {
|
311 |
+
|
312 |
+
// Retrieve the nonce value.
|
313 |
+
// @codingStandardsIgnoreStart
|
314 |
+
$nonce = isset( $_POST[ $this->nonce_name ] ) ?
|
315 |
+
filter_var( $_POST[ $this->nonce_name ], FILTER_SANITIZE_STRING )
|
316 |
+
: '';
|
317 |
+
// @codingStandardsIgnoreEnd
|
318 |
+
|
319 |
+
// If nonce has not been send, just return nothing else to do here.
|
320 |
+
// The method may be hooked to a wp action, so it's executed on every page request.
|
321 |
+
if ( ! $nonce ) {
|
322 |
+
return false;
|
323 |
+
}
|
324 |
+
|
325 |
+
// Die in case the nonce has been passed but not a valid one.
|
326 |
+
// @codingStandardsIgnoreLine
|
327 |
+
if ( ! wp_verify_nonce( $_POST[ $this->nonce_name ], $this->nonce_action ) ) {
|
328 |
+
wp_die( 'Cheating Uh?' );
|
329 |
+
}
|
330 |
+
|
331 |
+
$this->max_execution->set();
|
332 |
+
|
333 |
+
// Get the action to perform.
|
334 |
+
// @codingStandardsIgnoreLine
|
335 |
+
$action = isset( $_POST['action'] ) ? filter_var( $_POST['action'], FILTER_SANITIZE_STRING ) : '';
|
336 |
+
|
337 |
+
if ( 'download_file' !== $action ) {
|
338 |
+
return false;
|
339 |
+
}
|
340 |
+
|
341 |
+
$sql_file = '';
|
342 |
+
$compress = false;
|
343 |
+
|
344 |
+
// @codingStandardsIgnoreLine
|
345 |
+
if ( isset( $_POST['sql_file'] ) ) {
|
346 |
+
// @codingStandardsIgnoreLine
|
347 |
+
$sql_file = sanitize_file_name( $_POST['sql_file'] );
|
348 |
+
}
|
349 |
+
|
350 |
+
if ( ! $sql_file ) {
|
351 |
+
wp_die( esc_html__( 'The file you are looking for doesn\'t exists.', 'search-and-replace' ) );
|
352 |
+
}
|
353 |
+
|
354 |
+
// If file name contains path or does not end with '.sql' exit.
|
355 |
+
// @ToDo create a function to prevent traversal path.
|
356 |
+
$ext = strrchr( $sql_file, '.' );
|
357 |
+
if ( false !== strpos( $sql_file, '/' ) || '.sql' !== $ext ) {
|
358 |
+
wp_die( 'Cheating Uh?' );
|
359 |
+
}
|
360 |
+
|
361 |
+
// @codingStandardsIgnoreLine
|
362 |
+
if ( isset( $_POST['compress'] ) ) {
|
363 |
+
// @codingStandardsIgnoreLine
|
364 |
+
$compress = (bool) filter_var( $_POST['compress'], FILTER_VALIDATE_BOOLEAN );
|
365 |
+
}
|
366 |
+
|
367 |
+
// Download the file.
|
368 |
+
$this->dbe->deliver_backup( $sql_file, $compress );
|
369 |
+
|
370 |
+
$this->max_execution->restore();
|
371 |
+
|
372 |
+
return true;
|
373 |
+
}
|
374 |
+
}
|
inc/Page/AbstractPage.php
CHANGED
@@ -1,98 +1,98 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace Inpsyde\SearchReplace\Page;
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Class AbstractPage
|
7 |
-
*
|
8 |
-
* @package Inpsyde\SearchReplace\Page
|
9 |
-
*/
|
10 |
-
abstract class AbstractPage {
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Returns the translated title for the page.
|
14 |
-
*
|
15 |
-
* @return string
|
16 |
-
*/
|
17 |
-
abstract public function get_page_title();
|
18 |
-
|
19 |
-
/**
|
20 |
-
* By default "Search & Replace". Can be overwritten in child-classes.
|
21 |
-
*
|
22 |
-
* @return string
|
23 |
-
*/
|
24 |
-
public function get_menu_title() {
|
25 |
-
|
26 |
-
return esc_html__( 'Search & Replace', 'search-and-replace' );
|
27 |
-
}
|
28 |
-
|
29 |
-
/**
|
30 |
-
* @var array
|
31 |
-
*/
|
32 |
-
protected $errors = array();
|
33 |
-
|
34 |
-
/**
|
35 |
-
* @param string $msg
|
36 |
-
*/
|
37 |
-
public function add_error( $msg ) {
|
38 |
-
|
39 |
-
$this->errors[] = (string) $msg;
|
40 |
-
}
|
41 |
-
|
42 |
-
/**
|
43 |
-
* Echoes the content of the $errors array as formatted HTML if it contains error messages.
|
44 |
-
*/
|
45 |
-
public function display_errors() {
|
46 |
-
|
47 |
-
if ( count( $this->errors ) < 1 ) {
|
48 |
-
return;
|
49 |
-
}
|
50 |
-
|
51 |
-
?>
|
52 |
-
<div class="error notice is-dismissible">
|
53 |
-
<p>
|
54 |
-
<strong>
|
55 |
-
<?php esc_html_e( 'Errors:', 'search-and-replace' ); ?>
|
56 |
-
</strong>
|
57 |
-
</p>
|
58 |
-
<ul>
|
59 |
-
<?php foreach ( $this->errors as $error ) : ?>
|
60 |
-
<li><?= esc_html( $error ); ?></li>
|
61 |
-
<?php endforeach; ?>
|
62 |
-
</ul>
|
63 |
-
</div>
|
64 |
-
|
65 |
-
<?php
|
66 |
-
}
|
67 |
-
|
68 |
-
/**
|
69 |
-
* Displays the html for the submit button.
|
70 |
-
*
|
71 |
-
* @param string $name
|
72 |
-
*/
|
73 |
-
public function show_submit_button( $name = 'submit' ) {
|
74 |
-
|
75 |
-
printf(
|
76 |
-
'<input type="hidden" name="action" value="%s" />',
|
77 |
-
esc_attr( $this->get_slug() )
|
78 |
-
);
|
79 |
-
submit_button( $this->get_submit_button_title(), 'primary', $name );
|
80 |
-
wp_nonce_field( 'replace_domain', 'insr_nonce' );
|
81 |
-
}
|
82 |
-
|
83 |
-
/**
|
84 |
-
* @return string
|
85 |
-
*/
|
86 |
-
protected function get_submit_button_title() {
|
87 |
-
|
88 |
-
return esc_html__( 'Submit', 'search-replace' );
|
89 |
-
}
|
90 |
-
|
91 |
-
/**
|
92 |
-
* @return string
|
93 |
-
*/
|
94 |
-
public function get_slug() {
|
95 |
-
|
96 |
-
return sanitize_title_with_dashes( $this->get_page_title() );
|
97 |
-
}
|
98 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Inpsyde\SearchReplace\Page;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class AbstractPage
|
7 |
+
*
|
8 |
+
* @package Inpsyde\SearchReplace\Page
|
9 |
+
*/
|
10 |
+
abstract class AbstractPage {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Returns the translated title for the page.
|
14 |
+
*
|
15 |
+
* @return string
|
16 |
+
*/
|
17 |
+
abstract public function get_page_title();
|
18 |
+
|
19 |
+
/**
|
20 |
+
* By default "Search & Replace". Can be overwritten in child-classes.
|
21 |
+
*
|
22 |
+
* @return string
|
23 |
+
*/
|
24 |
+
public function get_menu_title() {
|
25 |
+
|
26 |
+
return esc_html__( 'Search & Replace', 'search-and-replace' );
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @var array
|
31 |
+
*/
|
32 |
+
protected $errors = array();
|
33 |
+
|
34 |
+
/**
|
35 |
+
* @param string $msg
|
36 |
+
*/
|
37 |
+
public function add_error( $msg ) {
|
38 |
+
|
39 |
+
$this->errors[] = (string) $msg;
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Echoes the content of the $errors array as formatted HTML if it contains error messages.
|
44 |
+
*/
|
45 |
+
public function display_errors() {
|
46 |
+
|
47 |
+
if ( count( $this->errors ) < 1 ) {
|
48 |
+
return;
|
49 |
+
}
|
50 |
+
|
51 |
+
?>
|
52 |
+
<div class="error notice is-dismissible">
|
53 |
+
<p>
|
54 |
+
<strong>
|
55 |
+
<?php esc_html_e( 'Errors:', 'search-and-replace' ); ?>
|
56 |
+
</strong>
|
57 |
+
</p>
|
58 |
+
<ul>
|
59 |
+
<?php foreach ( $this->errors as $error ) : ?>
|
60 |
+
<li><?= esc_html( $error ); ?></li>
|
61 |
+
<?php endforeach; ?>
|
62 |
+
</ul>
|
63 |
+
</div>
|
64 |
+
|
65 |
+
<?php
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Displays the html for the submit button.
|
70 |
+
*
|
71 |
+
* @param string $name
|
72 |
+
*/
|
73 |
+
public function show_submit_button( $name = 'submit' ) {
|
74 |
+
|
75 |
+
printf(
|
76 |
+
'<input type="hidden" name="action" value="%s" />',
|
77 |
+
esc_attr( $this->get_slug() )
|
78 |
+
);
|
79 |
+
submit_button( $this->get_submit_button_title(), 'primary', $name );
|
80 |
+
wp_nonce_field( 'replace_domain', 'insr_nonce' );
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* @return string
|
85 |
+
*/
|
86 |
+
protected function get_submit_button_title() {
|
87 |
+
|
88 |
+
return esc_html__( 'Submit', 'search-replace' );
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* @return string
|
93 |
+
*/
|
94 |
+
public function get_slug() {
|
95 |
+
|
96 |
+
return sanitize_title_with_dashes( $this->get_page_title() );
|
97 |
+
}
|
98 |
+
}
|
inc/Page/BackupDatabase.php
CHANGED
@@ -1,81 +1,81 @@
|
|
1 |
-
<?php
|
2 |
-
namespace Inpsyde\SearchReplace\Page;
|
3 |
-
|
4 |
-
use Inpsyde\SearchReplace\Database;
|
5 |
-
use Inpsyde\SearchReplace\FileDownloader;
|
6 |
-
|
7 |
-
/**
|
8 |
-
* Class BackupDatabase
|
9 |
-
*
|
10 |
-
* @package Inpsyde\SearchReplace\Page
|
11 |
-
*/
|
12 |
-
class BackupDatabase extends AbstractPage implements PageInterface {
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @var Database\Exporter
|
16 |
-
*/
|
17 |
-
private $dbe;
|
18 |
-
|
19 |
-
/**
|
20 |
-
* @var FileDownloader
|
21 |
-
*/
|
22 |
-
private $downloader;
|
23 |
-
|
24 |
-
/**
|
25 |
-
* BackupDatabase constructor.
|
26 |
-
*
|
27 |
-
* @param Database\Exporter $dbe
|
28 |
-
* @param FileDownloader $downloader
|
29 |
-
*/
|
30 |
-
public function __construct( Database\Exporter $dbe, FileDownloader $downloader ) {
|
31 |
-
|
32 |
-
$this->dbe = $dbe;
|
33 |
-
$this->downloader = $downloader;
|
34 |
-
}
|
35 |
-
|
36 |
-
/**
|
37 |
-
* @return string
|
38 |
-
*/
|
39 |
-
public function get_page_title() {
|
40 |
-
|
41 |
-
return esc_html__( 'Backup Database', 'search-and-replace' );
|
42 |
-
}
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Return the static slug string.
|
46 |
-
*
|
47 |
-
* @return string
|
48 |
-
*/
|
49 |
-
public function get_slug() {
|
50 |
-
|
51 |
-
return 'backup-database';
|
52 |
-
}
|
53 |
-
|
54 |
-
/**
|
55 |
-
* Shows the page template
|
56 |
-
*/
|
57 |
-
public function render() {
|
58 |
-
|
59 |
-
require_once( __DIR__ . '/../templates/db-backup.php' );
|
60 |
-
}
|
61 |
-
|
62 |
-
/**
|
63 |
-
* @return string
|
64 |
-
*/
|
65 |
-
protected function get_submit_button_title() {
|
66 |
-
|
67 |
-
return esc_html__( 'Create SQL File', 'search-and-replace' );
|
68 |
-
}
|
69 |
-
|
70 |
-
/**
|
71 |
-
* Event handler for click on export sql button
|
72 |
-
*/
|
73 |
-
public function save() {
|
74 |
-
|
75 |
-
$report = $this->dbe->db_backup();
|
76 |
-
$this->downloader->show_modal( $report );
|
77 |
-
|
78 |
-
return TRUE;
|
79 |
-
}
|
80 |
-
|
81 |
-
}
|
1 |
+
<?php
|
2 |
+
namespace Inpsyde\SearchReplace\Page;
|
3 |
+
|
4 |
+
use Inpsyde\SearchReplace\Database;
|
5 |
+
use Inpsyde\SearchReplace\FileDownloader;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Class BackupDatabase
|
9 |
+
*
|
10 |
+
* @package Inpsyde\SearchReplace\Page
|
11 |
+
*/
|
12 |
+
class BackupDatabase extends AbstractPage implements PageInterface {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @var Database\Exporter
|
16 |
+
*/
|
17 |
+
private $dbe;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* @var FileDownloader
|
21 |
+
*/
|
22 |
+
private $downloader;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* BackupDatabase constructor.
|
26 |
+
*
|
27 |
+
* @param Database\Exporter $dbe
|
28 |
+
* @param FileDownloader $downloader
|
29 |
+
*/
|
30 |
+
public function __construct( Database\Exporter $dbe, FileDownloader $downloader ) {
|
31 |
+
|
32 |
+
$this->dbe = $dbe;
|
33 |
+
$this->downloader = $downloader;
|
34 |
+
}
|
35 |
+
|
36 |
+
/**
|
37 |
+
* @return string
|
38 |
+
*/
|
39 |
+
public function get_page_title() {
|
40 |
+
|
41 |
+
return esc_html__( 'Backup Database', 'search-and-replace' );
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Return the static slug string.
|
46 |
+
*
|
47 |
+
* @return string
|
48 |
+
*/
|
49 |
+
public function get_slug() {
|
50 |
+
|
51 |
+
return 'backup-database';
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Shows the page template
|
56 |
+
*/
|
57 |
+
public function render() {
|
58 |
+
|
59 |
+
require_once( __DIR__ . '/../templates/db-backup.php' );
|
60 |
+
}
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @return string
|
64 |
+
*/
|
65 |
+
protected function get_submit_button_title() {
|
66 |
+
|
67 |
+
return esc_html__( 'Create SQL File', 'search-and-replace' );
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Event handler for click on export sql button
|
72 |
+
*/
|
73 |
+
public function save() {
|
74 |
+
|
75 |
+
$report = $this->dbe->db_backup();
|
76 |
+
$this->downloader->show_modal( $report );
|
77 |
+
|
78 |
+
return TRUE;
|
79 |
+
}
|
80 |
+
|
81 |
+
}
|
inc/Page/Credits.php
CHANGED
@@ -1,44 +1,44 @@
|
|
1 |
-
<?php
|
2 |
-
namespace Inpsyde\SearchReplace\Page;
|
3 |
-
|
4 |
-
/**
|
5 |
-
* Class Credits
|
6 |
-
*
|
7 |
-
* @package Inpsyde\SearchReplace\Page
|
8 |
-
*/
|
9 |
-
class Credits extends AbstractPage implements PageInterface {
|
10 |
-
|
11 |
-
/**
|
12 |
-
* Callback function for credits content.
|
13 |
-
*/
|
14 |
-
public function render() {
|
15 |
-
|
16 |
-
require_once( __DIR__ . '/../templates/credits.php' );
|
17 |
-
}
|
18 |
-
|
19 |
-
/**
|
20 |
-
* @return string
|
21 |
-
*/
|
22 |
-
public function get_page_title() {
|
23 |
-
|
24 |
-
return esc_html__( 'Credits', 'search-and-replace' );
|
25 |
-
}
|
26 |
-
|
27 |
-
/**
|
28 |
-
* Return the static slug string.
|
29 |
-
*
|
30 |
-
* @return string
|
31 |
-
*/
|
32 |
-
public function get_slug() {
|
33 |
-
|
34 |
-
return 'credits';
|
35 |
-
}
|
36 |
-
|
37 |
-
/**
|
38 |
-
* @return boolean
|
39 |
-
*/
|
40 |
-
public function save() {
|
41 |
-
|
42 |
-
return TRUE;
|
43 |
-
}
|
44 |
-
}
|
1 |
+
<?php
|
2 |
+
namespace Inpsyde\SearchReplace\Page;
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Class Credits
|
6 |
+
*
|
7 |
+
* @package Inpsyde\SearchReplace\Page
|
8 |
+
*/
|
9 |
+
class Credits extends AbstractPage implements PageInterface {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* Callback function for credits content.
|
13 |
+
*/
|
14 |
+
public function render() {
|
15 |
+
|
16 |
+
require_once( __DIR__ . '/../templates/credits.php' );
|
17 |
+
}
|
18 |
+
|
19 |
+
/**
|
20 |
+
* @return string
|
21 |
+
*/
|
22 |
+
public function get_page_title() {
|
23 |
+
|
24 |
+
return esc_html__( 'Credits', 'search-and-replace' );
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Return the static slug string.
|
29 |
+
*
|
30 |
+
* @return string
|
31 |
+
*/
|
32 |
+
public function get_slug() {
|
33 |
+
|
34 |
+
return 'credits';
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* @return boolean
|
39 |
+
*/
|
40 |
+
public function save() {
|
41 |
+
|
42 |
+
return TRUE;
|
43 |
+
}
|
44 |
+
}
|
inc/Page/Manager.php
CHANGED
@@ -1,193 +1,193 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace Inpsyde\SearchReplace\Page;
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Class Manager
|
7 |
-
*
|
8 |
-
* @package Inpsyde\SearchReplace\Page
|
9 |
-
*/
|
10 |
-
class Manager {
|
11 |
-
|
12 |
-
/**
|
13 |
-
* @var PageInterface[]
|
14 |
-
*/
|
15 |
-
private $pages = [];
|
16 |
-
|
17 |
-
/**
|
18 |
-
* Add page.
|
19 |
-
*
|
20 |
-
* @param PageInterface $page
|
21 |
-
*/
|
22 |
-
public function add_page( PageInterface $page ) {
|
23 |
-
|
24 |
-
$this->pages[ $page->get_slug() ] = $page;
|
25 |
-
}
|
26 |
-
|
27 |
-
/**
|
28 |
-
* Handling the POST-Request and save the data.
|
29 |
-
*/
|
30 |
-
public function save() {
|
31 |
-
|
32 |
-
if ( $_SERVER[ 'REQUEST_METHOD' ] !== 'POST' ) {
|
33 |
-
return;
|
34 |
-
}
|
35 |
-
|
36 |
-
$page = filter_input( INPUT_POST, 'action' );
|
37 |
-
if ( '' === $page ) {
|
38 |
-
return;
|
39 |
-
}
|
40 |
-
|
41 |
-
if ( ! isset( $this->pages[ $page ] ) ) {
|
42 |
-
return;
|
43 |
-
}
|
44 |
-
|
45 |
-
if ( ! check_admin_referer( 'replace_domain', 'insr_nonce' ) ) {
|
46 |
-
return;
|
47 |
-
}
|
48 |
-
|
49 |
-
/** @var PageInterface */
|
50 |
-
$this->pages[ $page ]->save();
|
51 |
-
}
|
52 |
-
|
53 |
-
/**
|
54 |
-
* Register all Pages.
|
55 |
-
*
|
56 |
-
* @wp-hook admin_menu
|
57 |
-
*/
|
58 |
-
public function register_pages() {
|
59 |
-
|
60 |
-
foreach ( $this->pages as $slug => $page ) {
|
61 |
-
|
62 |
-
/**
|
63 |
-
* @param string $cap
|
64 |
-
* @param PageInterface $page
|
65 |
-
*/
|
66 |
-
$cap = apply_filters( 'insr-capability', 'manage_options', $page );
|
67 |
-
|
68 |
-
add_submenu_page(
|
69 |
-
'tools.php',
|
70 |
-
$page->get_page_title(),
|
71 |
-
$page->get_menu_title(),
|
72 |
-
$cap,
|
73 |
-
$slug,
|
74 |
-
[ $this, 'render' ]
|
75 |
-
);
|
76 |
-
}
|
77 |
-
}
|
78 |
-
|
79 |
-
/**
|
80 |
-
* Removes the plugins sub-menu pages from admin menu.
|
81 |
-
*
|
82 |
-
* @wp-hook admin_head
|
83 |
-
*/
|
84 |
-
public function remove_submenu_pages() {
|
85 |
-
|
86 |
-
$i = 0;
|
87 |
-
foreach ( $this->pages as $slug => $page ) {
|
88 |
-
if ( $i > 0 ) {
|
89 |
-
remove_submenu_page( 'tools.php', $slug );
|
90 |
-
}
|
91 |
-
$i ++;
|
92 |
-
}
|
93 |
-
}
|
94 |
-
|
95 |
-
/**
|
96 |
-
* Render all pages and handling save.
|
97 |
-
*/
|
98 |
-
public function render() {
|
99 |
-
|
100 |
-
$url = admin_url( 'tools.php' );
|
101 |
-
$current_page = isset( $_GET[ 'page' ] ) ? $_GET[ 'page' ] : key( $this->pages );
|
102 |
-
|
103 |
-
$output = '<div class="wrap">';
|
104 |
-
$output .= '<h1 id="title">' . esc_html__( 'Search & Replace', 'search-and-replace' ) . '</h1>';
|
105 |
-
$output .= '<h2 class="nav-tab-wrapper">';
|
106 |
-
|
107 |
-
foreach ( $this->pages as $slug => $page ) :
|
108 |
-
$class = $current_page === $slug ? 'nav-tab-active' : '';
|
109 |
-
$output .= sprintf(
|
110 |
-
'<a class="nav-tab %1$s" href="%2$s">%3$s</a>',
|
111 |
-
esc_attr( $class ),
|
112 |
-
add_query_arg( 'page', $slug, $url ),
|
113 |
-
$page->get_page_title()
|
114 |
-
);
|
115 |
-
endforeach;
|
116 |
-
unset( $page );
|
117 |
-
|
118 |
-
$output .= '</h2>';
|
119 |
-
|
120 |
-
// Set the current page.
|
121 |
-
$page = $this->pages[ $current_page ];
|
122 |
-
|
123 |
-
echo $output;
|
124 |
-
echo '<div class="tab__content">';
|
125 |
-
$this->save();
|
126 |
-
$page->display_errors();
|
127 |
-
$page->render();
|
128 |
-
echo '</div>';
|
129 |
-
echo '</div>'; // wrap
|
130 |
-
}
|
131 |
-
|
132 |
-
/**
|
133 |
-
* Registers the Plugin stylesheet.
|
134 |
-
*
|
135 |
-
* @wp-hook admin_enqueue_scripts
|
136 |
-
*/
|
137 |
-
public function register_css() {
|
138 |
-
|
139 |
-
if ( ! $this->is_search_and_replace_admin_page() ) {
|
140 |
-
return;
|
141 |
-
}
|
142 |
-
|
143 |
-
$suffix = $this->get_script_suffix();
|
144 |
-
$url = ( SEARCH_REPLACE_BASEDIR . '/assets/css/inpsyde-search-replace' . $suffix . '.css' );
|
145 |
-
$handle = 'insr-styles';
|
146 |
-
|
147 |
-
wp_register_script( $handle, $url );
|
148 |
-
wp_enqueue_style( $handle, $url, [], false, false );
|
149 |
-
}
|
150 |
-
|
151 |
-
/**
|
152 |
-
* Registers the Plugin javascript.
|
153 |
-
*
|
154 |
-
* @wp-hook admin_enqueue_scripts
|
155 |
-
*/
|
156 |
-
public function register_js() {
|
157 |
-
|
158 |
-
if ( ! $this->is_search_and_replace_admin_page() ) {
|
159 |
-
return;
|
160 |
-
}
|
161 |
-
|
162 |
-
$suffix = $this->get_script_suffix();
|
163 |
-
$url = ( SEARCH_REPLACE_BASEDIR . '/assets/js/inpsyde-search-replace' . $suffix . '.js' );
|
164 |
-
$handle = 'insr-js';
|
165 |
-
|
166 |
-
wp_register_script( $handle, $url );
|
167 |
-
wp_enqueue_script( $handle, $url, [], false, true );
|
168 |
-
}
|
169 |
-
|
170 |
-
/**
|
171 |
-
* Get script suffix to difference between live and debug files.
|
172 |
-
*
|
173 |
-
* @return string
|
174 |
-
*/
|
175 |
-
private function get_script_suffix() {
|
176 |
-
|
177 |
-
return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
|
178 |
-
}
|
179 |
-
|
180 |
-
/**
|
181 |
-
* Is admin search and replace page
|
182 |
-
*
|
183 |
-
* Check against the current screen in admin,
|
184 |
-
*
|
185 |
-
* @return bool True if current screen is one of the search and replace pages
|
186 |
-
*/
|
187 |
-
private function is_search_and_replace_admin_page() {
|
188 |
-
|
189 |
-
$current = str_replace( 'tools_page_', '', get_current_screen()->id );
|
190 |
-
|
191 |
-
return array_key_exists( $current, $this->pages );
|
192 |
-
}
|
193 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Inpsyde\SearchReplace\Page;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class Manager
|
7 |
+
*
|
8 |
+
* @package Inpsyde\SearchReplace\Page
|
9 |
+
*/
|
10 |
+
class Manager {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @var PageInterface[]
|
14 |
+
*/
|
15 |
+
private $pages = [];
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Add page.
|
19 |
+
*
|
20 |
+
* @param PageInterface $page
|
21 |
+
*/
|
22 |
+
public function add_page( PageInterface $page ) {
|
23 |
+
|
24 |
+
$this->pages[ $page->get_slug() ] = $page;
|
25 |
+
}
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Handling the POST-Request and save the data.
|
29 |
+
*/
|
30 |
+
public function save() {
|
31 |
+
|
32 |
+
if ( $_SERVER[ 'REQUEST_METHOD' ] !== 'POST' ) {
|
33 |
+
return;
|
34 |
+
}
|
35 |
+
|
36 |
+
$page = filter_input( INPUT_POST, 'action' );
|
37 |
+
if ( '' === $page ) {
|
38 |
+
return;
|
39 |
+
}
|
40 |
+
|
41 |
+
if ( ! isset( $this->pages[ $page ] ) ) {
|
42 |
+
return;
|
43 |
+
}
|
44 |
+
|
45 |
+
if ( ! check_admin_referer( 'replace_domain', 'insr_nonce' ) ) {
|
46 |
+
return;
|
47 |
+
}
|
48 |
+
|
49 |
+
/** @var PageInterface */
|
50 |
+
$this->pages[ $page ]->save();
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Register all Pages.
|
55 |
+
*
|
56 |
+
* @wp-hook admin_menu
|
57 |
+
*/
|
58 |
+
public function register_pages() {
|
59 |
+
|
60 |
+
foreach ( $this->pages as $slug => $page ) {
|
61 |
+
|
62 |
+
/**
|
63 |
+
* @param string $cap
|
64 |
+
* @param PageInterface $page
|
65 |
+
*/
|
66 |
+
$cap = apply_filters( 'insr-capability', 'manage_options', $page );
|
67 |
+
|
68 |
+
add_submenu_page(
|
69 |
+
'tools.php',
|
70 |
+
$page->get_page_title(),
|
71 |
+
$page->get_menu_title(),
|
72 |
+
$cap,
|
73 |
+
$slug,
|
74 |
+
[ $this, 'render' ]
|
75 |
+
);
|
76 |
+
}
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Removes the plugins sub-menu pages from admin menu.
|
81 |
+
*
|
82 |
+
* @wp-hook admin_head
|
83 |
+
*/
|
84 |
+
public function remove_submenu_pages() {
|
85 |
+
|
86 |
+
$i = 0;
|
87 |
+
foreach ( $this->pages as $slug => $page ) {
|
88 |
+
if ( $i > 0 ) {
|
89 |
+
remove_submenu_page( 'tools.php', $slug );
|
90 |
+
}
|
91 |
+
$i ++;
|
92 |
+
}
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Render all pages and handling save.
|
97 |
+
*/
|
98 |
+
public function render() {
|
99 |
+
|
100 |
+
$url = admin_url( 'tools.php' );
|
101 |
+
$current_page = isset( $_GET[ 'page' ] ) ? $_GET[ 'page' ] : key( $this->pages );
|
102 |
+
|
103 |
+
$output = '<div class="wrap">';
|
104 |
+
$output .= '<h1 id="title">' . esc_html__( 'Search & Replace', 'search-and-replace' ) . '</h1>';
|
105 |
+
$output .= '<h2 class="nav-tab-wrapper">';
|
106 |
+
|
107 |
+
foreach ( $this->pages as $slug => $page ) :
|
108 |
+
$class = $current_page === $slug ? 'nav-tab-active' : '';
|
109 |
+
$output .= sprintf(
|
110 |
+
'<a class="nav-tab %1$s" href="%2$s">%3$s</a>',
|
111 |
+
esc_attr( $class ),
|
112 |
+
add_query_arg( 'page', $slug, $url ),
|
113 |
+
$page->get_page_title()
|
114 |
+
);
|
115 |
+
endforeach;
|
116 |
+
unset( $page );
|
117 |
+
|
118 |
+
$output .= '</h2>';
|
119 |
+
|
120 |
+
// Set the current page.
|
121 |
+
$page = $this->pages[ $current_page ];
|
122 |
+
|
123 |
+
echo $output;
|
124 |
+
echo '<div class="tab__content">';
|
125 |
+
$this->save();
|
126 |
+
$page->display_errors();
|
127 |
+
$page->render();
|
128 |
+
echo '</div>';
|
129 |
+
echo '</div>'; // wrap
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Registers the Plugin stylesheet.
|
134 |
+
*
|
135 |
+
* @wp-hook admin_enqueue_scripts
|
136 |
+
*/
|
137 |
+
public function register_css() {
|
138 |
+
|
139 |
+
if ( ! $this->is_search_and_replace_admin_page() ) {
|
140 |
+
return;
|
141 |
+
}
|
142 |
+
|
143 |
+
$suffix = $this->get_script_suffix();
|
144 |
+
$url = ( SEARCH_REPLACE_BASEDIR . '/assets/css/inpsyde-search-replace' . $suffix . '.css' );
|
145 |
+
$handle = 'insr-styles';
|
146 |
+
|
147 |
+
wp_register_script( $handle, $url );
|
148 |
+
wp_enqueue_style( $handle, $url, [], false, false );
|
149 |
+
}
|
150 |
+
|
151 |
+
/**
|
152 |
+
* Registers the Plugin javascript.
|
153 |
+
*
|
154 |
+
* @wp-hook admin_enqueue_scripts
|
155 |
+
*/
|
156 |
+
public function register_js() {
|
157 |
+
|
158 |
+
if ( ! $this->is_search_and_replace_admin_page() ) {
|
159 |
+
return;
|
160 |
+
}
|
161 |
+
|
162 |
+
$suffix = $this->get_script_suffix();
|
163 |
+
$url = ( SEARCH_REPLACE_BASEDIR . '/assets/js/inpsyde-search-replace' . $suffix . '.js' );
|
164 |
+
$handle = 'insr-js';
|
165 |
+
|
166 |
+
wp_register_script( $handle, $url );
|
167 |
+
wp_enqueue_script( $handle, $url, [], false, true );
|
168 |
+
}
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Get script suffix to difference between live and debug files.
|
172 |
+
*
|
173 |
+
* @return string
|
174 |
+
*/
|
175 |
+
private function get_script_suffix() {
|
176 |
+
|
177 |
+
return defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
|
178 |
+
}
|
179 |
+
|
180 |
+
/**
|
181 |
+
* Is admin search and replace page
|
182 |
+
*
|
183 |
+
* Check against the current screen in admin,
|
184 |
+
*
|
185 |
+
* @return bool True if current screen is one of the search and replace pages
|
186 |
+
*/
|
187 |
+
private function is_search_and_replace_admin_page() {
|
188 |
+
|
189 |
+
$current = str_replace( 'tools_page_', '', get_current_screen()->id );
|
190 |
+
|
191 |
+
return array_key_exists( $current, $this->pages );
|
192 |
+
}
|
193 |
+
}
|
inc/Page/PageInterface.php
CHANGED
@@ -1,54 +1,54 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace Inpsyde\SearchReplace\Page;
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Interface PageInterface
|
7 |
-
*
|
8 |
-
* @package Inpsyde\SearchReplace\Page
|
9 |
-
*/
|
10 |
-
interface PageInterface {
|
11 |
-
|
12 |
-
/**
|
13 |
-
* @param string $msg
|
14 |
-
*/
|
15 |
-
public function add_error( $msg );
|
16 |
-
|
17 |
-
/**
|
18 |
-
* Echoes the content of the $errors array as formatted HTML if it contains error messages.
|
19 |
-
*/
|
20 |
-
public function display_errors();
|
21 |
-
|
22 |
-
/**
|
23 |
-
* Returns the translated Menu title for add_submenu_page().
|
24 |
-
*
|
25 |
-
* @return string
|
26 |
-
*/
|
27 |
-
public function get_menu_title();
|
28 |
-
|
29 |
-
/**
|
30 |
-
* Returns the translated title for the page.
|
31 |
-
*
|
32 |
-
* @return string
|
33 |
-
*/
|
34 |
-
public function get_page_title();
|
35 |
-
|
36 |
-
/**
|
37 |
-
* Returns the page_slug for add_submenu_page().
|
38 |
-
*
|
39 |
-
* @return string
|
40 |
-
*/
|
41 |
-
public function get_slug();
|
42 |
-
|
43 |
-
/**
|
44 |
-
* Rendering the page content.
|
45 |
-
*/
|
46 |
-
public function render();
|
47 |
-
|
48 |
-
/**
|
49 |
-
* Saving the data.
|
50 |
-
*
|
51 |
-
* @return boolean
|
52 |
-
*/
|
53 |
-
public function save();
|
54 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Inpsyde\SearchReplace\Page;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Interface PageInterface
|
7 |
+
*
|
8 |
+
* @package Inpsyde\SearchReplace\Page
|
9 |
+
*/
|
10 |
+
interface PageInterface {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* @param string $msg
|
14 |
+
*/
|
15 |
+
public function add_error( $msg );
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Echoes the content of the $errors array as formatted HTML if it contains error messages.
|
19 |
+
*/
|
20 |
+
public function display_errors();
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Returns the translated Menu title for add_submenu_page().
|
24 |
+
*
|
25 |
+
* @return string
|
26 |
+
*/
|
27 |
+
public function get_menu_title();
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Returns the translated title for the page.
|
31 |
+
*
|
32 |
+
* @return string
|
33 |
+
*/
|
34 |
+
public function get_page_title();
|
35 |
+
|
36 |
+
/**
|
37 |
+
* Returns the page_slug for add_submenu_page().
|
38 |
+
*
|
39 |
+
* @return string
|
40 |
+
*/
|
41 |
+
public function get_slug();
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Rendering the page content.
|
45 |
+
*/
|
46 |
+
public function render();
|
47 |
+
|
48 |
+
/**
|
49 |
+
* Saving the data.
|
50 |
+
*
|
51 |
+
* @return boolean
|
52 |
+
*/
|
53 |
+
public function save();
|
54 |
+
}
|
inc/Page/ReplaceDomain.php
CHANGED
@@ -1,112 +1,112 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace Inpsyde\SearchReplace\Page;
|
4 |
-
|
5 |
-
use Inpsyde\SearchReplace\Database;
|
6 |
-
use Inpsyde\SearchReplace\FileDownloader;
|
7 |
-
|
8 |
-
/**
|
9 |
-
* Class ReplaceDomain
|
10 |
-
*
|
11 |
-
* @package Inpsyde\SearchReplace\inc\Page
|
12 |
-
*/
|
13 |
-
class ReplaceDomain extends AbstractPage implements PageInterface {
|
14 |
-
|
15 |
-
/**
|
16 |
-
* @var \Inpsyde\SearchReplace\Database\Exporter
|
17 |
-
*/
|
18 |
-
private $dbe;
|
19 |
-
|
20 |
-
/**
|
21 |
-
* @var Manager
|
22 |
-
*/
|
23 |
-
private $dbm;
|
24 |
-
|
25 |
-
/**
|
26 |
-
* @var FileDownloader
|
27 |
-
*/
|
28 |
-
private $downloader;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* ReplaceDomain constructor.
|
32 |
-
*
|
33 |
-
* @param Database\Manager $dbm
|
34 |
-
* @param Database\Exporter $dbe
|
35 |
-
* @param FileDownloader $downloader
|
36 |
-
*/
|
37 |
-
public function __construct( Database\Manager $dbm, Database\Exporter $dbe, FileDownloader $downloader ) {
|
38 |
-
|
39 |
-
$this->dbm = $dbm;
|
40 |
-
$this->dbe = $dbe;
|
41 |
-
$this->downloader = $downloader;
|
42 |
-
}
|
43 |
-
|
44 |
-
/**
|
45 |
-
* @return bool
|
46 |
-
* @throws \Throwable
|
47 |
-
*/
|
48 |
-
public function save() {
|
49 |
-
|
50 |
-
$search = esc_url_raw( filter_input( INPUT_POST, 'search' ) );
|
51 |
-
$replace = esc_url_raw( filter_input( INPUT_POST, 'replace' ) );
|
52 |
-
$new_db_prefix = esc_attr( filter_input( INPUT_POST, 'new_db_prefix' ) );
|
53 |
-
|
54 |
-
// search field should not be empty
|
55 |
-
if ( '' === $replace ) {
|
56 |
-
$this->add_error( esc_html__( 'Replace Field should not be empty.', 'search-and-replace' ) );
|
57 |
-
|
58 |
-
return false;
|
59 |
-
}
|
60 |
-
|
61 |
-
// Do not pass the new db prefix if `change_db_prefix` isn't flagged.
|
62 |
-
// @codingStandardsIgnoreStart
|
63 |
-
$change_db_prefix = isset( $_POST[ 'change_db_prefix' ] ) ?
|
64 |
-
filter_var( $_POST[ 'change_db_prefix' ], FILTER_VALIDATE_BOOLEAN ) :
|
65 |
-
false;
|
66 |
-
// @codingStandardsIgnoreEnd
|
67 |
-
|
68 |
-
$new_db_prefix = $change_db_prefix ? $new_db_prefix : '';
|
69 |
-
|
70 |
-
// Make the backup.
|
71 |
-
$report = $this->dbe->db_backup( $search, $replace, [], true, $new_db_prefix );
|
72 |
-
|
73 |
-
// Show the replace report.
|
74 |
-
$this->downloader->show_modal( $report );
|
75 |
-
|
76 |
-
return true;
|
77 |
-
}
|
78 |
-
|
79 |
-
/**
|
80 |
-
* Shows the page template
|
81 |
-
*/
|
82 |
-
public function render() {
|
83 |
-
|
84 |
-
require_once __DIR__ . '/../templates/replace-domain.php';
|
85 |
-
}
|
86 |
-
|
87 |
-
/**
|
88 |
-
* @return string
|
89 |
-
*/
|
90 |
-
protected function get_submit_button_title() {
|
91 |
-
|
92 |
-
return esc_html__( 'Do Replace Domain/Url', 'search-and-replace' );
|
93 |
-
}
|
94 |
-
|
95 |
-
/**
|
96 |
-
* @return string
|
97 |
-
*/
|
98 |
-
public function get_page_title() {
|
99 |
-
|
100 |
-
return esc_html__( 'Replace Domain URL', 'search-and-replace' );
|
101 |
-
}
|
102 |
-
|
103 |
-
/**
|
104 |
-
* Return the static slug string.
|
105 |
-
*
|
106 |
-
* @return string
|
107 |
-
*/
|
108 |
-
public function get_slug() {
|
109 |
-
|
110 |
-
return 'replace-domain-url';
|
111 |
-
}
|
112 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Inpsyde\SearchReplace\Page;
|
4 |
+
|
5 |
+
use Inpsyde\SearchReplace\Database;
|
6 |
+
use Inpsyde\SearchReplace\FileDownloader;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class ReplaceDomain
|
10 |
+
*
|
11 |
+
* @package Inpsyde\SearchReplace\inc\Page
|
12 |
+
*/
|
13 |
+
class ReplaceDomain extends AbstractPage implements PageInterface {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @var \Inpsyde\SearchReplace\Database\Exporter
|
17 |
+
*/
|
18 |
+
private $dbe;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @var Manager
|
22 |
+
*/
|
23 |
+
private $dbm;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @var FileDownloader
|
27 |
+
*/
|
28 |
+
private $downloader;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* ReplaceDomain constructor.
|
32 |
+
*
|
33 |
+
* @param Database\Manager $dbm
|
34 |
+
* @param Database\Exporter $dbe
|
35 |
+
* @param FileDownloader $downloader
|
36 |
+
*/
|
37 |
+
public function __construct( Database\Manager $dbm, Database\Exporter $dbe, FileDownloader $downloader ) {
|
38 |
+
|
39 |
+
$this->dbm = $dbm;
|
40 |
+
$this->dbe = $dbe;
|
41 |
+
$this->downloader = $downloader;
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* @return bool
|
46 |
+
* @throws \Throwable
|
47 |
+
*/
|
48 |
+
public function save() {
|
49 |
+
|
50 |
+
$search = esc_url_raw( filter_input( INPUT_POST, 'search' ) );
|
51 |
+
$replace = esc_url_raw( filter_input( INPUT_POST, 'replace' ) );
|
52 |
+
$new_db_prefix = esc_attr( filter_input( INPUT_POST, 'new_db_prefix' ) );
|
53 |
+
|
54 |
+
// search field should not be empty
|
55 |
+
if ( '' === $replace ) {
|
56 |
+
$this->add_error( esc_html__( 'Replace Field should not be empty.', 'search-and-replace' ) );
|
57 |
+
|
58 |
+
return false;
|
59 |
+
}
|
60 |
+
|
61 |
+
// Do not pass the new db prefix if `change_db_prefix` isn't flagged.
|
62 |
+
// @codingStandardsIgnoreStart
|
63 |
+
$change_db_prefix = isset( $_POST[ 'change_db_prefix' ] ) ?
|
64 |
+
filter_var( $_POST[ 'change_db_prefix' ], FILTER_VALIDATE_BOOLEAN ) :
|
65 |
+
false;
|
66 |
+
// @codingStandardsIgnoreEnd
|
67 |
+
|
68 |
+
$new_db_prefix = $change_db_prefix ? $new_db_prefix : '';
|
69 |
+
|
70 |
+
// Make the backup.
|
71 |
+
$report = $this->dbe->db_backup( $search, $replace, [], true, $new_db_prefix );
|
72 |
+
|
73 |
+
// Show the replace report.
|
74 |
+
$this->downloader->show_modal( $report );
|
75 |
+
|
76 |
+
return true;
|
77 |
+
}
|
78 |
+
|
79 |
+
/**
|
80 |
+
* Shows the page template
|
81 |
+
*/
|
82 |
+
public function render() {
|
83 |
+
|
84 |
+
require_once __DIR__ . '/../templates/replace-domain.php';
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* @return string
|
89 |
+
*/
|
90 |
+
protected function get_submit_button_title() {
|
91 |
+
|
92 |
+
return esc_html__( 'Do Replace Domain/Url', 'search-and-replace' );
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* @return string
|
97 |
+
*/
|
98 |
+
public function get_page_title() {
|
99 |
+
|
100 |
+
return esc_html__( 'Replace Domain URL', 'search-and-replace' );
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Return the static slug string.
|
105 |
+
*
|
106 |
+
* @return string
|
107 |
+
*/
|
108 |
+
public function get_slug() {
|
109 |
+
|
110 |
+
return 'replace-domain-url';
|
111 |
+
}
|
112 |
+
}
|
inc/Page/SearchReplace.php
CHANGED
@@ -1,340 +1,340 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace Inpsyde\SearchReplace\Page;
|
4 |
-
|
5 |
-
use Inpsyde\SearchReplace\Database;
|
6 |
-
use Inpsyde\SearchReplace\FileDownloader;
|
7 |
-
|
8 |
-
/**
|
9 |
-
* Class SearchReplace
|
10 |
-
*
|
11 |
-
* @package Inpsyde\SearchReplace\Page
|
12 |
-
*/
|
13 |
-
class SearchReplace extends AbstractPage implements PageInterface {
|
14 |
-
|
15 |
-
/**
|
16 |
-
* @var Manager
|
17 |
-
*/
|
18 |
-
private $dbm;
|
19 |
-
|
20 |
-
/**
|
21 |
-
* @var $replace
|
22 |
-
*/
|
23 |
-
private $replace;
|
24 |
-
|
25 |
-
/**
|
26 |
-
* @var $dbe
|
27 |
-
*/
|
28 |
-
private $dbe;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* @var FileDownloader
|
32 |
-
*/
|
33 |
-
private $downloader;
|
34 |
-
|
35 |
-
/**
|
36 |
-
* BackupDatabase constructor.
|
37 |
-
*
|
38 |
-
* @param Database\Manager $dbm
|
39 |
-
* @param Database\Replace $replace
|
40 |
-
* @param Database\Exporter $dbe
|
41 |
-
* @param FileDownloader $downloader
|
42 |
-
*/
|
43 |
-
public function __construct( Database\Manager $dbm, Database\Replace $replace, Database\Exporter $dbe, FileDownloader $downloader ) {
|
44 |
-
|
45 |
-
$this->dbm = $dbm;
|
46 |
-
$this->replace = $replace;
|
47 |
-
$this->dbe = $dbe;
|
48 |
-
$this->downloader = $downloader;
|
49 |
-
}
|
50 |
-
|
51 |
-
/**
|
52 |
-
* Shows the page contents
|
53 |
-
*/
|
54 |
-
public function render() {
|
55 |
-
|
56 |
-
require_once __DIR__ . '/../templates/search-replace.php';
|
57 |
-
|
58 |
-
wp_localize_script(
|
59 |
-
'insr-js',
|
60 |
-
'insr_data_obj', [
|
61 |
-
'search_matches_site_url' => __(
|
62 |
-
'Your search contains your current site url. Replacing your site url can cause your site to break. Are you sure you wish to proceed?',
|
63 |
-
'search-and-replace'
|
64 |
-
),
|
65 |
-
'site_url' => $this->get_stripped_site_url(),
|
66 |
-
]
|
67 |
-
);
|
68 |
-
}
|
69 |
-
|
70 |
-
/**
|
71 |
-
* Returns the site url, strips http:// or https://
|
72 |
-
*/
|
73 |
-
private function get_stripped_site_url() {
|
74 |
-
|
75 |
-
$url = get_site_url();
|
76 |
-
|
77 |
-
return substr( $url, strpos( $url, '/' ) + 2 );
|
78 |
-
}
|
79 |
-
|
80 |
-
/**
|
81 |
-
* @return string
|
82 |
-
*/
|
83 |
-
public function get_page_title() {
|
84 |
-
|
85 |
-
return esc_html__( 'Search & Replace', 'search-and-replace' );
|
86 |
-
}
|
87 |
-
|
88 |
-
/**
|
89 |
-
* Return the static slug string.
|
90 |
-
*
|
91 |
-
* @return string
|
92 |
-
*/
|
93 |
-
public function get_slug() {
|
94 |
-
|
95 |
-
return 'search-replace';
|
96 |
-
}
|
97 |
-
|
98 |
-
/**
|
99 |
-
* @return bool
|
100 |
-
* @throws \Throwable
|
101 |
-
*/
|
102 |
-
public function save() {
|
103 |
-
|
104 |
-
if ( ! $this->is_request_valid() ) {
|
105 |
-
return false;
|
106 |
-
}
|
107 |
-
|
108 |
-
// Retrieve tables.
|
109 |
-
$tables = $this->selected_tables();
|
110 |
-
if ( ! $tables ) {
|
111 |
-
return false;
|
112 |
-
}
|
113 |
-
|
114 |
-
// @codingStandardsIgnoreLine
|
115 |
-
$dry_run = isset( $_POST[ 'dry_run' ] ) ? true : false;
|
116 |
-
|
117 |
-
// remove wp_magic_quotes
|
118 |
-
$search = stripslashes( filter_input( INPUT_POST, 'search' ) );
|
119 |
-
$replace = stripslashes( filter_input( INPUT_POST, 'replace' ) );
|
120 |
-
$csv = stripslashes( filter_input( INPUT_POST, 'csv' ) );
|
121 |
-
$csv = ( $csv === '' ? null : $csv );
|
122 |
-
|
123 |
-
// Do not perform anything if we haven't anything.
|
124 |
-
if ( ( ! $search && ! $replace ) && ! $csv ) {
|
125 |
-
$this->add_error( esc_html__( 'You must provide at least a search string or a csv data', 'search-and-replace' ) );
|
126 |
-
return false;
|
127 |
-
}
|
128 |
-
|
129 |
-
// If dry run is checked we run the replace function with dry run and return
|
130 |
-
if ( true === $dry_run ) {
|
131 |
-
$this->run_replace( $search, $replace, $tables, $dry_run, $csv );
|
132 |
-
|
133 |
-
return false;
|
134 |
-
}
|
135 |
-
|
136 |
-
$export_or_save = filter_input( INPUT_POST, 'export_or_save' );
|
137 |
-
|
138 |
-
if ( 'export' === $export_or_save ) {
|
139 |
-
// 'export'-button was checked
|
140 |
-
$report = $this->dbe->db_backup( $search, $replace, $tables, false, '', $csv );
|
141 |
-
$this->downloader->show_modal( $report );
|
142 |
-
} else {
|
143 |
-
// "Save changes to database" was checked
|
144 |
-
$this->run_replace( $search, $replace, $tables, $dry_run, $csv );
|
145 |
-
}
|
146 |
-
|
147 |
-
return true;
|
148 |
-
}
|
149 |
-
|
150 |
-
/**
|
151 |
-
* Checks the input form and writes possible errors to a WP_Error object
|
152 |
-
*
|
153 |
-
* @return bool true|false
|
154 |
-
*/
|
155 |
-
protected function is_request_valid() {
|
156 |
-
|
157 |
-
// If not table are selected mark the request as invalid but let user know why.
|
158 |
-
if ( ! $this->selected_tables() ) {
|
159 |
-
$this->add_error(
|
160 |
-
esc_html__(
|
161 |
-
'No Tables were selected. You must select at least one table to perform the action.',
|
162 |
-
'search-and-replace'
|
163 |
-
)
|
164 |
-
);
|
165 |
-
|
166 |
-
return false;
|
167 |
-
}
|
168 |
-
|
169 |
-
$search = filter_input( INPUT_POST, 'search' );
|
170 |
-
$replace = filter_input( INPUT_POST, 'replace' );
|
171 |
-
|
172 |
-
// if search field is empty and replace field is not empty quit. If both fields are empty, go on (useful for backup of single tables without changing)
|
173 |
-
if ( '' === $search && '' !== $replace ) {
|
174 |
-
$this->add_error( esc_attr__( 'Search field is empty.', 'search-and-replace' ) );
|
175 |
-
|
176 |
-
return false;
|
177 |
-
}
|
178 |
-
|
179 |
-
return true;
|
180 |
-
}
|
181 |
-
|
182 |
-
/**
|
183 |
-
* Calls run_replace_table() on each table provided in array $tables.
|
184 |
-
*
|
185 |
-
* @param string $search
|
186 |
-
* @param string $replace
|
187 |
-
* @param array $tables Array of tables we want to search.
|
188 |
-
* @param bool $dry_run True if dry run (no changes are written to db).
|
189 |
-
* @param bool $csv
|
190 |
-
*
|
191 |
-
* @throws \Throwable
|
192 |
-
*/
|
193 |
-
protected function run_replace( $search, $replace, $tables, $dry_run, $csv = null ) {
|
194 |
-
|
195 |
-
echo '<div class="updated notice is-dismissible">';
|
196 |
-
if ( $dry_run ) {
|
197 |
-
echo '<p><strong>'
|
198 |
-
. esc_html__(
|
199 |
-
'Dry run is selected. No changes were made to the database and no SQL file was written .',
|
200 |
-
'search-and-replace'
|
201 |
-
)
|
202 |
-
. '</strong></p>';
|
203 |
-
|
204 |
-
} else {
|
205 |
-
echo '<p><strong>'
|
206 |
-
. esc_html__(
|
207 |
-
'The following changes were made to the database: ',
|
208 |
-
'search-and-replace'
|
209 |
-
)
|
210 |
-
. '</strong></p>';
|
211 |
-
}
|
212 |
-
$this->replace->set_dry_run( $dry_run );
|
213 |
-
|
214 |
-
$report = $this->replace->run_search_replace( $search, $replace, $tables, $csv );
|
215 |
-
|
216 |
-
if ( is_wp_error( $report ) ) {
|
217 |
-
$this->add_error( $report->get_error_message() );
|
218 |
-
} else {
|
219 |
-
if ( count( $report[ 'changes' ] ) > 0 ) {
|
220 |
-
$this->downloader->show_changes( $report );
|
221 |
-
}
|
222 |
-
|
223 |
-
// if no changes found report that
|
224 |
-
if ( 0 === count( $report [ 'changes' ] ) ) {
|
225 |
-
echo '<p>' . esc_html__( 'Search pattern not found.', 'search-and-replace' ) . '</p>';
|
226 |
-
}
|
227 |
-
}
|
228 |
-
|
229 |
-
echo '</div>';
|
230 |
-
}
|
231 |
-
|
232 |
-
/**
|
233 |
-
* Prints a select with all the tables and their sizes
|
234 |
-
*
|
235 |
-
* @return void
|
236 |
-
*/
|
237 |
-
protected function show_table_list() {
|
238 |
-
|
239 |
-
$tables = $this->dbm->get_tables();
|
240 |
-
$sizes = $this->dbm->get_sizes();
|
241 |
-
$table_count = count( $tables );
|
242 |
-
|
243 |
-
// adjust height of select according to table count, but max 20 rows
|
244 |
-
$select_rows = $table_count < 20 ? $table_count : 20;
|
245 |
-
// if we come from a dry run, we select the tables to the dry run again
|
246 |
-
$selected_tables = $this->selected_tables();
|
247 |
-
|
248 |
-
echo '<select id="select_tables" name="select_tables[]" multiple="multiple" size = "' . $select_rows . '">';
|
249 |
-
foreach ( $tables as $table ) {
|
250 |
-
$table_size = isset ( $sizes[ $table ] ) ? $sizes[ $table ] : '';
|
251 |
-
// check if dry run. if dry run && current table is in "selected" array add selected attribute
|
252 |
-
$selected = ( isset( $_POST[ 'dry_run' ] )
|
253 |
-
&& $selected_tables
|
254 |
-
&& in_array( $table, $selected_tables, false )
|
255 |
-
)
|
256 |
-
? 'selected="selected"'
|
257 |
-
: '';
|
258 |
-
|
259 |
-
printf(
|
260 |
-
"<option value='%s' %s>%s</option>",
|
261 |
-
esc_attr( $table ),
|
262 |
-
$selected,
|
263 |
-
esc_html( $table . $table_size )
|
264 |
-
);
|
265 |
-
|
266 |
-
}
|
267 |
-
echo '</select>';
|
268 |
-
}
|
269 |
-
|
270 |
-
/**
|
271 |
-
* @return string
|
272 |
-
*/
|
273 |
-
protected function get_submit_button_title() {
|
274 |
-
|
275 |
-
return esc_html__( 'Do Search & Replace', 'search-and-replace' );
|
276 |
-
}
|
277 |
-
|
278 |
-
/**
|
279 |
-
* Shows the search value in template.
|
280 |
-
*/
|
281 |
-
private function get_search_value() {
|
282 |
-
|
283 |
-
$search = isset( $_POST[ 'search' ] ) ? $_POST[ 'search' ] : '';
|
284 |
-
$dry_run = isset( $_POST[ 'dry_run' ] ) ? true : false;
|
285 |
-
|
286 |
-
if ( $dry_run ) {
|
287 |
-
$search = stripslashes( $search );
|
288 |
-
$search = htmlentities( $search );
|
289 |
-
echo $search;
|
290 |
-
}
|
291 |
-
|
292 |
-
}
|
293 |
-
|
294 |
-
/**
|
295 |
-
* Shows the replace value in template
|
296 |
-
*/
|
297 |
-
private function get_replace_value() {
|
298 |
-
|
299 |
-
$replace = isset( $_POST[ 'replace' ] ) ? $_POST[ 'replace' ] : '';
|
300 |
-
$dry_run = isset( $_POST[ 'dry_run' ] ) ? true : false;
|
301 |
-
if ( $dry_run ) {
|
302 |
-
$replace = stripslashes( $replace );
|
303 |
-
$replace = htmlentities( $replace );
|
304 |
-
echo $replace;
|
305 |
-
}
|
306 |
-
|
307 |
-
}
|
308 |
-
|
309 |
-
/**
|
310 |
-
* Shows the csv value in template.
|
311 |
-
*/
|
312 |
-
private function get_csv_value() {
|
313 |
-
|
314 |
-
$csv = isset( $_POST[ 'csv' ] ) ? $_POST[ 'csv' ] : '';
|
315 |
-
$dry_run = isset( $_POST[ 'dry_run' ] ) ? true : false;
|
316 |
-
if ( $dry_run ) {
|
317 |
-
$csv = stripslashes( $csv );
|
318 |
-
$csv = htmlentities( $csv );
|
319 |
-
echo $csv;
|
320 |
-
}
|
321 |
-
|
322 |
-
}
|
323 |
-
|
324 |
-
/**
|
325 |
-
* Retrieve Selected Tables
|
326 |
-
*
|
327 |
-
* @return array The tables list from the POST request
|
328 |
-
*/
|
329 |
-
private function selected_tables() {
|
330 |
-
|
331 |
-
$tables = [];
|
332 |
-
|
333 |
-
if ( ! empty( $_POST[ 'select_tables' ] ) ) {
|
334 |
-
$tables = filter_var( $_POST[ 'select_tables' ], FILTER_SANITIZE_STRING, FILTER_REQUIRE_ARRAY );
|
335 |
-
}
|
336 |
-
|
337 |
-
return $tables;
|
338 |
-
}
|
339 |
-
|
340 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Inpsyde\SearchReplace\Page;
|
4 |
+
|
5 |
+
use Inpsyde\SearchReplace\Database;
|
6 |
+
use Inpsyde\SearchReplace\FileDownloader;
|
7 |
+
|
8 |
+
/**
|
9 |
+
* Class SearchReplace
|
10 |
+
*
|
11 |
+
* @package Inpsyde\SearchReplace\Page
|
12 |
+
*/
|
13 |
+
class SearchReplace extends AbstractPage implements PageInterface {
|
14 |
+
|
15 |
+
/**
|
16 |
+
* @var Manager
|
17 |
+
*/
|
18 |
+
private $dbm;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @var $replace
|
22 |
+
*/
|
23 |
+
private $replace;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @var $dbe
|
27 |
+
*/
|
28 |
+
private $dbe;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @var FileDownloader
|
32 |
+
*/
|
33 |
+
private $downloader;
|
34 |
+
|
35 |
+
/**
|
36 |
+
* BackupDatabase constructor.
|
37 |
+
*
|
38 |
+
* @param Database\Manager $dbm
|
39 |
+
* @param Database\Replace $replace
|
40 |
+
* @param Database\Exporter $dbe
|
41 |
+
* @param FileDownloader $downloader
|
42 |
+
*/
|
43 |
+
public function __construct( Database\Manager $dbm, Database\Replace $replace, Database\Exporter $dbe, FileDownloader $downloader ) {
|
44 |
+
|
45 |
+
$this->dbm = $dbm;
|
46 |
+
$this->replace = $replace;
|
47 |
+
$this->dbe = $dbe;
|
48 |
+
$this->downloader = $downloader;
|
49 |
+
}
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Shows the page contents
|
53 |
+
*/
|
54 |
+
public function render() {
|
55 |
+
|
56 |
+
require_once __DIR__ . '/../templates/search-replace.php';
|
57 |
+
|
58 |
+
wp_localize_script(
|
59 |
+
'insr-js',
|
60 |
+
'insr_data_obj', [
|
61 |
+
'search_matches_site_url' => __(
|
62 |
+
'Your search contains your current site url. Replacing your site url can cause your site to break. Are you sure you wish to proceed?',
|
63 |
+
'search-and-replace'
|
64 |
+
),
|
65 |
+
'site_url' => $this->get_stripped_site_url(),
|
66 |
+
]
|
67 |
+
);
|
68 |
+
}
|
69 |
+
|
70 |
+
/**
|
71 |
+
* Returns the site url, strips http:// or https://
|
72 |
+
*/
|
73 |
+
private function get_stripped_site_url() {
|
74 |
+
|
75 |
+
$url = get_site_url();
|
76 |
+
|
77 |
+
return substr( $url, strpos( $url, '/' ) + 2 );
|
78 |
+
}
|
79 |
+
|
80 |
+
/**
|
81 |
+
* @return string
|
82 |
+
*/
|
83 |
+
public function get_page_title() {
|
84 |
+
|
85 |
+
return esc_html__( 'Search & Replace', 'search-and-replace' );
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Return the static slug string.
|
90 |
+
*
|
91 |
+
* @return string
|
92 |
+
*/
|
93 |
+
public function get_slug() {
|
94 |
+
|
95 |
+
return 'search-replace';
|
96 |
+
}
|
97 |
+
|
98 |
+
/**
|
99 |
+
* @return bool
|
100 |
+
* @throws \Throwable
|
101 |
+
*/
|
102 |
+
public function save() {
|
103 |
+
|
104 |
+
if ( ! $this->is_request_valid() ) {
|
105 |
+
return false;
|
106 |
+
}
|
107 |
+
|
108 |
+
// Retrieve tables.
|
109 |
+
$tables = $this->selected_tables();
|
110 |
+
if ( ! $tables ) {
|
111 |
+
return false;
|
112 |
+
}
|
113 |
+
|
114 |
+
// @codingStandardsIgnoreLine
|
115 |
+
$dry_run = isset( $_POST[ 'dry_run' ] ) ? true : false;
|
116 |
+
|
117 |
+
// remove wp_magic_quotes
|
118 |
+
$search = stripslashes( filter_input( INPUT_POST, 'search' ) );
|
119 |
+
$replace = stripslashes( filter_input( INPUT_POST, 'replace' ) );
|
120 |
+
$csv = stripslashes( filter_input( INPUT_POST, 'csv' ) );
|
121 |
+
$csv = ( $csv === '' ? null : $csv );
|
122 |
+
|
123 |
+
// Do not perform anything if we haven't anything.
|
124 |
+
if ( ( ! $search && ! $replace ) && ! $csv ) {
|
125 |
+
$this->add_error( esc_html__( 'You must provide at least a search string or a csv data', 'search-and-replace' ) );
|
126 |
+
return false;
|
127 |
+
}
|
128 |
+
|
129 |
+
// If dry run is checked we run the replace function with dry run and return
|
130 |
+
if ( true === $dry_run ) {
|
131 |
+
$this->run_replace( $search, $replace, $tables, $dry_run, $csv );
|
132 |
+
|
133 |
+
return false;
|
134 |
+
}
|
135 |
+
|
136 |
+
$export_or_save = filter_input( INPUT_POST, 'export_or_save' );
|
137 |
+
|
138 |
+
if ( 'export' === $export_or_save ) {
|
139 |
+
// 'export'-button was checked
|
140 |
+
$report = $this->dbe->db_backup( $search, $replace, $tables, false, '', $csv );
|
141 |
+
$this->downloader->show_modal( $report );
|
142 |
+
} else {
|
143 |
+
// "Save changes to database" was checked
|
144 |
+
$this->run_replace( $search, $replace, $tables, $dry_run, $csv );
|
145 |
+
}
|
146 |
+
|
147 |
+
return true;
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Checks the input form and writes possible errors to a WP_Error object
|
152 |
+
*
|
153 |
+
* @return bool true|false
|
154 |
+
*/
|
155 |
+
protected function is_request_valid() {
|
156 |
+
|
157 |
+
// If not table are selected mark the request as invalid but let user know why.
|
158 |
+
if ( ! $this->selected_tables() ) {
|
159 |
+
$this->add_error(
|
160 |
+
esc_html__(
|
161 |
+
'No Tables were selected. You must select at least one table to perform the action.',
|
162 |
+
'search-and-replace'
|
163 |
+
)
|
164 |
+
);
|
165 |
+
|
166 |
+
return false;
|
167 |
+
}
|
168 |
+
|
169 |
+
$search = filter_input( INPUT_POST, 'search' );
|
170 |
+
$replace = filter_input( INPUT_POST, 'replace' );
|
171 |
+
|
172 |
+
// if search field is empty and replace field is not empty quit. If both fields are empty, go on (useful for backup of single tables without changing)
|
173 |
+
if ( '' === $search && '' !== $replace ) {
|
174 |
+
$this->add_error( esc_attr__( 'Search field is empty.', 'search-and-replace' ) );
|
175 |
+
|
176 |
+
return false;
|
177 |
+
}
|
178 |
+
|
179 |
+
return true;
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Calls run_replace_table() on each table provided in array $tables.
|
184 |
+
*
|
185 |
+
* @param string $search
|
186 |
+
* @param string $replace
|
187 |
+
* @param array $tables Array of tables we want to search.
|
188 |
+
* @param bool $dry_run True if dry run (no changes are written to db).
|
189 |
+
* @param bool $csv
|
190 |
+
*
|
191 |
+
* @throws \Throwable
|
192 |
+
*/
|
193 |
+
protected function run_replace( $search, $replace, $tables, $dry_run, $csv = null ) {
|
194 |
+
|
195 |
+
echo '<div class="updated notice is-dismissible">';
|
196 |
+
if ( $dry_run ) {
|
197 |
+
echo '<p><strong>'
|
198 |
+
. esc_html__(
|
199 |
+
'Dry run is selected. No changes were made to the database and no SQL file was written .',
|
200 |
+
'search-and-replace'
|
201 |
+
)
|
202 |
+
. '</strong></p>';
|
203 |
+
|
204 |
+
} else {
|
205 |
+
echo '<p><strong>'
|
206 |
+
. esc_html__(
|
207 |
+
'The following changes were made to the database: ',
|
208 |
+
'search-and-replace'
|
209 |
+
)
|
210 |
+
. '</strong></p>';
|
211 |
+
}
|
212 |
+
$this->replace->set_dry_run( $dry_run );
|
213 |
+
|
214 |
+
$report = $this->replace->run_search_replace( $search, $replace, $tables, $csv );
|
215 |
+
|
216 |
+
if ( is_wp_error( $report ) ) {
|
217 |
+
$this->add_error( $report->get_error_message() );
|
218 |
+
} else {
|
219 |
+
if ( count( $report[ 'changes' ] ) > 0 ) {
|
220 |
+
$this->downloader->show_changes( $report );
|
221 |
+
}
|
222 |
+
|
223 |
+
// if no changes found report that
|
224 |
+
if ( 0 === count( $report [ 'changes' ] ) ) {
|
225 |
+
echo '<p>' . esc_html__( 'Search pattern not found.', 'search-and-replace' ) . '</p>';
|
226 |
+
}
|
227 |
+
}
|
228 |
+
|
229 |
+
echo '</div>';
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Prints a select with all the tables and their sizes
|
234 |
+
*
|
235 |
+
* @return void
|
236 |
+
*/
|
237 |
+
protected function show_table_list() {
|
238 |
+
|
239 |
+
$tables = $this->dbm->get_tables();
|
240 |
+
$sizes = $this->dbm->get_sizes();
|
241 |
+
$table_count = count( $tables );
|
242 |
+
|
243 |
+
// adjust height of select according to table count, but max 20 rows
|
244 |
+
$select_rows = $table_count < 20 ? $table_count : 20;
|
245 |
+
// if we come from a dry run, we select the tables to the dry run again
|
246 |
+
$selected_tables = $this->selected_tables();
|
247 |
+
|
248 |
+
echo '<select id="select_tables" name="select_tables[]" multiple="multiple" size = "' . $select_rows . '">';
|
249 |
+
foreach ( $tables as $table ) {
|
250 |
+
$table_size = isset ( $sizes[ $table ] ) ? $sizes[ $table ] : '';
|
251 |
+
// check if dry run. if dry run && current table is in "selected" array add selected attribute
|
252 |
+
$selected = ( isset( $_POST[ 'dry_run' ] )
|
253 |
+
&& $selected_tables
|
254 |
+
&& in_array( $table, $selected_tables, false )
|
255 |
+
)
|
256 |
+
? 'selected="selected"'
|
257 |
+
: '';
|
258 |
+
|
259 |
+
printf(
|
260 |
+
"<option value='%s' %s>%s</option>",
|
261 |
+
esc_attr( $table ),
|
262 |
+
$selected,
|
263 |
+
esc_html( $table . $table_size )
|
264 |
+
);
|
265 |
+
|
266 |
+
}
|
267 |
+
echo '</select>';
|
268 |
+
}
|
269 |
+
|
270 |
+
/**
|
271 |
+
* @return string
|
272 |
+
*/
|
273 |
+
protected function get_submit_button_title() {
|
274 |
+
|
275 |
+
return esc_html__( 'Do Search & Replace', 'search-and-replace' );
|
276 |
+
}
|
277 |
+
|
278 |
+
/**
|
279 |
+
* Shows the search value in template.
|
280 |
+
*/
|
281 |
+
private function get_search_value() {
|
282 |
+
|
283 |
+
$search = isset( $_POST[ 'search' ] ) ? $_POST[ 'search' ] : '';
|
284 |
+
$dry_run = isset( $_POST[ 'dry_run' ] ) ? true : false;
|
285 |
+
|
286 |
+
if ( $dry_run ) {
|
287 |
+
$search = stripslashes( $search );
|
288 |
+
$search = htmlentities( $search );
|
289 |
+
echo $search;
|
290 |
+
}
|
291 |
+
|
292 |
+
}
|
293 |
+
|
294 |
+
/**
|
295 |
+
* Shows the replace value in template
|
296 |
+
*/
|
297 |
+
private function get_replace_value() {
|
298 |
+
|
299 |
+
$replace = isset( $_POST[ 'replace' ] ) ? $_POST[ 'replace' ] : '';
|
300 |
+
$dry_run = isset( $_POST[ 'dry_run' ] ) ? true : false;
|
301 |
+
if ( $dry_run ) {
|
302 |
+
$replace = stripslashes( $replace );
|
303 |
+
$replace = htmlentities( $replace );
|
304 |
+
echo $replace;
|
305 |
+
}
|
306 |
+
|
307 |
+
}
|
308 |
+
|
309 |
+
/**
|
310 |
+
* Shows the csv value in template.
|
311 |
+
*/
|
312 |
+
private function get_csv_value() {
|
313 |
+
|
314 |
+
$csv = isset( $_POST[ 'csv' ] ) ? $_POST[ 'csv' ] : '';
|
315 |
+
$dry_run = isset( $_POST[ 'dry_run' ] ) ? true : false;
|
316 |
+
if ( $dry_run ) {
|
317 |
+
$csv = stripslashes( $csv );
|
318 |
+
$csv = htmlentities( $csv );
|
319 |
+
echo $csv;
|
320 |
+
}
|
321 |
+
|
322 |
+
}
|
323 |
+
|
324 |
+
/**
|
325 |
+
* Retrieve Selected Tables
|
326 |
+
*
|
327 |
+
* @return array The tables list from the POST request
|
328 |
+
*/
|
329 |
+
private function selected_tables() {
|
330 |
+
|
331 |
+
$tables = [];
|
332 |
+
|
333 |
+
if ( ! empty( $_POST[ 'select_tables' ] ) ) {
|
334 |
+
$tables = filter_var( $_POST[ 'select_tables' ], FILTER_SANITIZE_STRING, FILTER_REQUIRE_ARRAY );
|
335 |
+
}
|
336 |
+
|
337 |
+
return $tables;
|
338 |
+
}
|
339 |
+
|
340 |
+
}
|
inc/Page/SqlImport.php
CHANGED
@@ -1,223 +1,223 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace Inpsyde\SearchReplace\Page;
|
4 |
-
|
5 |
-
use Inpsyde\SearchReplace\Database;
|
6 |
-
|
7 |
-
/**
|
8 |
-
* Class SqlImport
|
9 |
-
*
|
10 |
-
* @package Inpsyde\SearchReplace\inc\Page
|
11 |
-
*/
|
12 |
-
class SqlImport extends AbstractPage implements PageInterface {
|
13 |
-
|
14 |
-
/**
|
15 |
-
* @var Database\Importer
|
16 |
-
*/
|
17 |
-
private $dbi;
|
18 |
-
|
19 |
-
/**
|
20 |
-
* SqlImport constructor.
|
21 |
-
*
|
22 |
-
* @param Database\Importer $dbi
|
23 |
-
*/
|
24 |
-
public function __construct( Database\Importer $dbi ) {
|
25 |
-
|
26 |
-
$this->dbi = $dbi;
|
27 |
-
}
|
28 |
-
|
29 |
-
/**
|
30 |
-
* @return string
|
31 |
-
*/
|
32 |
-
public function get_page_title() {
|
33 |
-
|
34 |
-
return esc_html__( 'SQL Import', 'search-and-replace' );
|
35 |
-
}
|
36 |
-
|
37 |
-
/**
|
38 |
-
* Return the static slug string.
|
39 |
-
*
|
40 |
-
* @return string
|
41 |
-
*/
|
42 |
-
public function get_slug() {
|
43 |
-
|
44 |
-
return 'sql-import';
|
45 |
-
}
|
46 |
-
|
47 |
-
/**
|
48 |
-
* Callback function for menu item
|
49 |
-
*/
|
50 |
-
public function render() {
|
51 |
-
|
52 |
-
require_once dirname(__DIR__) . '/templates/sql-import.php';
|
53 |
-
}
|
54 |
-
|
55 |
-
/**
|
56 |
-
* @return string
|
57 |
-
*/
|
58 |
-
protected function get_submit_button_title() {
|
59 |
-
|
60 |
-
return esc_html__( 'Import SQL file', 'search-and-replace' );
|
61 |
-
}
|
62 |
-
|
63 |
-
/**
|
64 |
-
* {@inheritdoc}
|
65 |
-
*/
|
66 |
-
public function save() {
|
67 |
-
|
68 |
-
// @ToDo: Better handling of large files
|
69 |
-
// maybe like here: http://stackoverflow.com/questions/147821/loading-sql-files-from-within-php , answer by user 'gromo'
|
70 |
-
$php_upload_error_code = $_FILES[ 'file_to_upload' ][ 'error' ];
|
71 |
-
if ( 0 === $php_upload_error_code ) {
|
72 |
-
// get file extension
|
73 |
-
$ext = strrchr( $_FILES [ 'file_to_upload' ][ 'name' ], '.' );
|
74 |
-
// parse file
|
75 |
-
$tempfile = $_FILES [ 'file_to_upload' ][ 'tmp_name' ];
|
76 |
-
switch ( $ext ) {
|
77 |
-
case '.sql':
|
78 |
-
// @codingStandardsIgnoreLine
|
79 |
-
$sql_source = file_get_contents( $tempfile );
|
80 |
-
break;
|
81 |
-
case '.gz':
|
82 |
-
$sql_source = $this->read_gzfile_into_string( $tempfile );
|
83 |
-
break;
|
84 |
-
default:
|
85 |
-
$this->add_error(
|
86 |
-
esc_html__(
|
87 |
-
'The file has neither \'.gz\' nor \'.sql\' Extension. Import not possible.',
|
88 |
-
'search-and-replace'
|
89 |
-
)
|
90 |
-
);
|
91 |
-
return;
|
92 |
-
}
|
93 |
-
|
94 |
-
// call import function
|
95 |
-
$success = $this->dbi->import_sql( $sql_source );
|
96 |
-
if ( - 1 === $success ) {
|
97 |
-
$this->add_error(
|
98 |
-
esc_html__(
|
99 |
-
'The file does not seem to be a valid SQL file. Import not possible.',
|
100 |
-
'search-and-replace'
|
101 |
-
)
|
102 |
-
);
|
103 |
-
} else {
|
104 |
-
echo '<div class="updated notice is-dismissible">';
|
105 |
-
echo '<p>';
|
106 |
-
printf(
|
107 |
-
// Translators: %s print the sql source.
|
108 |
-
esc_html__(
|
109 |
-
'The SQL file was successfully imported. %s SQL queries were performed.',
|
110 |
-
'search-and-replace'
|
111 |
-
),
|
112 |
-
esc_html($success)
|
113 |
-
);
|
114 |
-
echo '</p></div>';
|
115 |
-
}
|
116 |
-
} else {
|
117 |
-
// show error
|
118 |
-
$php_upload_errors = array(
|
119 |
-
0 => esc_html__(
|
120 |
-
'There is no error, the file uploaded with success',
|
121 |
-
'search-and-replace'
|
122 |
-
),
|
123 |
-
1 => esc_html__(
|
124 |
-
'The uploaded file exceeds the upload_max_filesize directive in php.ini',
|
125 |
-
'search-and-replace'
|
126 |
-
),
|
127 |
-
2 => esc_html__(
|
128 |
-
'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
|
129 |
-
'search-and-replace'
|
130 |
-
),
|
131 |
-
3 => esc_html__(
|
132 |
-
'The uploaded file was only partially uploaded',
|
133 |
-
'search-and-replace'
|
134 |
-
),
|
135 |
-
4 => esc_html__(
|
136 |
-
'No file was uploaded.',
|
137 |
-
'search-and-replace'
|
138 |
-
),
|
139 |
-
6 => esc_html__(
|
140 |
-
'Missing a temporary folder.',
|
141 |
-
'search-and-replace'
|
142 |
-
),
|
143 |
-
7 => esc_html__(
|
144 |
-
'Failed to write file to disk.',
|
145 |
-
'search-and-replace' ),
|
146 |
-
8 => esc_html__(
|
147 |
-
'A PHP extension stopped the file upload.',
|
148 |
-
'search-and-replace'
|
149 |
-
),
|
150 |
-
);
|
151 |
-
|
152 |
-
$this->add_error(
|
153 |
-
sprintf(
|
154 |
-
// Translators: %s print the error message.
|
155 |
-
esc_html__( 'Upload Error: %s', 'search-and-replace' ),
|
156 |
-
$php_upload_errors[ $php_upload_error_code ]
|
157 |
-
)
|
158 |
-
);
|
159 |
-
}
|
160 |
-
|
161 |
-
}
|
162 |
-
|
163 |
-
/**
|
164 |
-
* Reads a gz file into a string.
|
165 |
-
*
|
166 |
-
* @param string $filename String path ot file.
|
167 |
-
*
|
168 |
-
* @return string The file contents.
|
169 |
-
*/
|
170 |
-
private function read_gzfile_into_string( $filename ) {
|
171 |
-
|
172 |
-
$zd = gzopen( $filename, 'r' );
|
173 |
-
$contents = gzread( $zd, 10000 );
|
174 |
-
gzclose( $zd );
|
175 |
-
|
176 |
-
return $contents;
|
177 |
-
}
|
178 |
-
|
179 |
-
/**
|
180 |
-
* Returns a file size limit in kilobytes based on the PHP upload_max_filesize and post_max_size.
|
181 |
-
*
|
182 |
-
* @link http://stackoverflow.com/questions/13076480/php-get-actual-maximum-upload-size
|
183 |
-
*
|
184 |
-
* @return float
|
185 |
-
*/
|
186 |
-
public function file_upload_max_size() {
|
187 |
-
|
188 |
-
$max_size = - 1;
|
189 |
-
|
190 |
-
if ( $max_size < 0 ) {
|
191 |
-
// Start with post_max_size.
|
192 |
-
$max_size = $this->parse_size( ini_get( 'post_max_size' ) );
|
193 |
-
|
194 |
-
// If upload_max_size is less, then reduce. Except if upload_max_size is
|
195 |
-
// zero, which indicates no limit.
|
196 |
-
$upload_max = $this->parse_size( ini_get( 'upload_max_filesize' ) );
|
197 |
-
if ( $upload_max > 0 && $upload_max < $max_size ) {
|
198 |
-
$max_size = $upload_max;
|
199 |
-
}
|
200 |
-
}
|
201 |
-
|
202 |
-
return $max_size / 1024;
|
203 |
-
}
|
204 |
-
|
205 |
-
/**
|
206 |
-
* @param int $size
|
207 |
-
*
|
208 |
-
* @return float
|
209 |
-
*/
|
210 |
-
private function parse_size( $size ) {
|
211 |
-
|
212 |
-
// Remove the non-unit characters from the size.
|
213 |
-
$unit = preg_replace( '/[^bkmgtpezy]/i', '', $size );
|
214 |
-
// Remove the non-numeric characters from the size.
|
215 |
-
$size = preg_replace( '/[^0-9\.]/', '', $size );
|
216 |
-
if ( $unit ) {
|
217 |
-
// Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
|
218 |
-
return round( $size * ( 1024 ** stripos( 'bkmgtpezy', $unit[0] ) ) );
|
219 |
-
}
|
220 |
-
return round( $size );
|
221 |
-
}
|
222 |
-
|
223 |
-
}
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace Inpsyde\SearchReplace\Page;
|
4 |
+
|
5 |
+
use Inpsyde\SearchReplace\Database;
|
6 |
+
|
7 |
+
/**
|
8 |
+
* Class SqlImport
|
9 |
+
*
|
10 |
+
* @package Inpsyde\SearchReplace\inc\Page
|
11 |
+
*/
|
12 |
+
class SqlImport extends AbstractPage implements PageInterface {
|
13 |
+
|
14 |
+
/**
|
15 |
+
* @var Database\Importer
|
16 |
+
*/
|
17 |
+
private $dbi;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* SqlImport constructor.
|
21 |
+
*
|
22 |
+
* @param Database\Importer $dbi
|
23 |
+
*/
|
24 |
+
public function __construct( Database\Importer $dbi ) {
|
25 |
+
|
26 |
+
$this->dbi = $dbi;
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @return string
|
31 |
+
*/
|
32 |
+
public function get_page_title() {
|
33 |
+
|
34 |
+
return esc_html__( 'SQL Import', 'search-and-replace' );
|
35 |
+
}
|
36 |
+
|
37 |
+
/**
|
38 |
+
* Return the static slug string.
|
39 |
+
*
|
40 |
+
* @return string
|
41 |
+
*/
|
42 |
+
public function get_slug() {
|
43 |
+
|
44 |
+
return 'sql-import';
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Callback function for menu item
|
49 |
+
*/
|
50 |
+
public function render() {
|
51 |
+
|
52 |
+
require_once dirname(__DIR__) . '/templates/sql-import.php';
|
53 |
+
}
|
54 |
+
|
55 |
+
/**
|
56 |
+
* @return string
|
57 |
+
*/
|
58 |
+
protected function get_submit_button_title() {
|
59 |
+
|
60 |
+
return esc_html__( 'Import SQL file', 'search-and-replace' );
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* {@inheritdoc}
|
65 |
+
*/
|
66 |
+
public function save() {
|
67 |
+
|
68 |
+
// @ToDo: Better handling of large files
|
69 |
+
// maybe like here: http://stackoverflow.com/questions/147821/loading-sql-files-from-within-php , answer by user 'gromo'
|
70 |
+
$php_upload_error_code = $_FILES[ 'file_to_upload' ][ 'error' ];
|
71 |
+
if ( 0 === $php_upload_error_code ) {
|
72 |
+
// get file extension
|
73 |
+
$ext = strrchr( $_FILES [ 'file_to_upload' ][ 'name' ], '.' );
|
74 |
+
// parse file
|
75 |
+
$tempfile = $_FILES [ 'file_to_upload' ][ 'tmp_name' ];
|
76 |
+
switch ( $ext ) {
|
77 |
+
case '.sql':
|
78 |
+
// @codingStandardsIgnoreLine
|
79 |
+
$sql_source = file_get_contents( $tempfile );
|
80 |
+
break;
|
81 |
+
case '.gz':
|
82 |
+
$sql_source = $this->read_gzfile_into_string( $tempfile );
|
83 |
+
break;
|
84 |
+
default:
|
85 |
+
$this->add_error(
|
86 |
+
esc_html__(
|
87 |
+
'The file has neither \'.gz\' nor \'.sql\' Extension. Import not possible.',
|
88 |
+
'search-and-replace'
|
89 |
+
)
|
90 |
+
);
|
91 |
+
return;
|
92 |
+
}
|
93 |
+
|
94 |
+
// call import function
|
95 |
+
$success = $this->dbi->import_sql( $sql_source );
|
96 |
+
if ( - 1 === $success ) {
|
97 |
+
$this->add_error(
|
98 |
+
esc_html__(
|
99 |
+
'The file does not seem to be a valid SQL file. Import not possible.',
|
100 |
+
'search-and-replace'
|
101 |
+
)
|
102 |
+
);
|
103 |
+
} else {
|
104 |
+
echo '<div class="updated notice is-dismissible">';
|
105 |
+
echo '<p>';
|
106 |
+
printf(
|
107 |
+
// Translators: %s print the sql source.
|
108 |
+
esc_html__(
|
109 |
+
'The SQL file was successfully imported. %s SQL queries were performed.',
|
110 |
+
'search-and-replace'
|
111 |
+
),
|
112 |
+
esc_html($success)
|
113 |
+
);
|
114 |
+
echo '</p></div>';
|
115 |
+
}
|
116 |
+
} else {
|
117 |
+
// show error
|
118 |
+
$php_upload_errors = array(
|
119 |
+
0 => esc_html__(
|
120 |
+
'There is no error, the file uploaded with success',
|
121 |
+
'search-and-replace'
|
122 |
+
),
|
123 |
+
1 => esc_html__(
|
124 |
+
'The uploaded file exceeds the upload_max_filesize directive in php.ini',
|
125 |
+
'search-and-replace'
|
126 |
+
),
|
127 |
+
2 => esc_html__(
|
128 |
+
'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form',
|
129 |
+
'search-and-replace'
|
130 |
+
),
|
131 |
+
3 => esc_html__(
|
132 |
+
'The uploaded file was only partially uploaded',
|
133 |
+
'search-and-replace'
|
134 |
+
),
|
135 |
+
4 => esc_html__(
|
136 |
+
'No file was uploaded.',
|
137 |
+
'search-and-replace'
|
138 |
+
),
|
139 |
+
6 => esc_html__(
|
140 |
+
'Missing a temporary folder.',
|
141 |
+
'search-and-replace'
|
142 |
+
),
|
143 |
+
7 => esc_html__(
|
144 |
+
'Failed to write file to disk.',
|
145 |
+
'search-and-replace' ),
|
146 |
+
8 => esc_html__(
|
147 |
+
'A PHP extension stopped the file upload.',
|
148 |
+
'search-and-replace'
|
149 |
+
),
|
150 |
+
);
|
151 |
+
|
152 |
+
$this->add_error(
|
153 |
+
sprintf(
|
154 |
+
// Translators: %s print the error message.
|
155 |
+
esc_html__( 'Upload Error: %s', 'search-and-replace' ),
|
156 |
+
$php_upload_errors[ $php_upload_error_code ]
|
157 |
+
)
|
158 |
+
);
|
159 |
+
}
|
160 |
+
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Reads a gz file into a string.
|
165 |
+
*
|
166 |
+
* @param string $filename String path ot file.
|
167 |
+
*
|
168 |
+
* @return string The file contents.
|
169 |
+
*/
|
170 |
+
private function read_gzfile_into_string( $filename ) {
|
171 |
+
|
172 |
+
$zd = gzopen( $filename, 'r' );
|
173 |
+
$contents = gzread( $zd, 10000 );
|
174 |
+
gzclose( $zd );
|
175 |
+
|
176 |
+
return $contents;
|
177 |
+
}
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Returns a file size limit in kilobytes based on the PHP upload_max_filesize and post_max_size.
|
181 |
+
*
|
182 |
+
* @link http://stackoverflow.com/questions/13076480/php-get-actual-maximum-upload-size
|
183 |
+
*
|
184 |
+
* @return float
|
185 |
+
*/
|
186 |
+
public function file_upload_max_size() {
|
187 |
+
|
188 |
+
$max_size = - 1;
|
189 |
+
|
190 |
+
if ( $max_size < 0 ) {
|
191 |
+
// Start with post_max_size.
|
192 |
+
$max_size = $this->parse_size( ini_get( 'post_max_size' ) );
|
193 |
+
|
194 |
+
// If upload_max_size is less, then reduce. Except if upload_max_size is
|
195 |
+
// zero, which indicates no limit.
|
196 |
+
$upload_max = $this->parse_size( ini_get( 'upload_max_filesize' ) );
|
197 |
+
if ( $upload_max > 0 && $upload_max < $max_size ) {
|
198 |
+
$max_size = $upload_max;
|
199 |
+
}
|
200 |
+
}
|
201 |
+
|
202 |
+
return $max_size / 1024;
|
203 |
+
}
|
204 |
+
|
205 |
+
/**
|
206 |
+
* @param int $size
|
207 |
+
*
|
208 |
+
* @return float
|
209 |
+
*/
|
210 |
+
private function parse_size( $size ) {
|
211 |
+
|
212 |
+
// Remove the non-unit characters from the size.
|
213 |
+
$unit = preg_replace( '/[^bkmgtpezy]/i', '', $size );
|
214 |
+
// Remove the non-numeric characters from the size.
|
215 |
+
$size = preg_replace( '/[^0-9\.]/', '', $size );
|
216 |
+
if ( $unit ) {
|
217 |
+
// Find the position of the unit in the ordered string which is the power of magnitude to multiply a kilobyte by.
|
218 |
+
return round( $size * ( 1024 ** stripos( 'bkmgtpezy', $unit[0] ) ) );
|
219 |
+
}
|
220 |
+
return round( $size );
|
221 |
+
}
|
222 |
+
|
223 |
+
}
|
inc/Service/MaxExecutionTime.php
CHANGED
@@ -1,49 +1,49 @@
|
|
1 |
-
<?php
|
2 |
-
namespace Inpsyde\SearchReplace\Service;
|
3 |
-
|
4 |
-
/**
|
5 |
-
* Class RunTime - set the service time out up to 0
|
6 |
-
*
|
7 |
-
* @package Inpsyde\SearchReplace\Service
|
8 |
-
*/
|
9 |
-
class MaxExecutionTime {
|
10 |
-
|
11 |
-
/**
|
12 |
-
* @var int
|
13 |
-
*/
|
14 |
-
private $met;
|
15 |
-
|
16 |
-
/**
|
17 |
-
* Store current timelimit and set a limit
|
18 |
-
*
|
19 |
-
* @param int $time
|
20 |
-
*/
|
21 |
-
public function set( $time = 0 ) {
|
22 |
-
|
23 |
-
if ( 0 === $time ) {
|
24 |
-
$this->store();
|
25 |
-
}
|
26 |
-
|
27 |
-
@set_time_limit( $time );
|
28 |
-
|
29 |
-
}
|
30 |
-
|
31 |
-
/**
|
32 |
-
* Restore timelimit.
|
33 |
-
*/
|
34 |
-
public function restore() {
|
35 |
-
|
36 |
-
$this->set( $this->met );
|
37 |
-
|
38 |
-
}
|
39 |
-
|
40 |
-
/**
|
41 |
-
* Fetch the max_execution_time from php.ini.
|
42 |
-
*/
|
43 |
-
public function store() {
|
44 |
-
|
45 |
-
$this->met = (int) ini_get( 'max_execution_time' );
|
46 |
-
|
47 |
-
}
|
48 |
-
|
49 |
-
}
|
1 |
+
<?php
|
2 |
+
namespace Inpsyde\SearchReplace\Service;
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Class RunTime - set the service time out up to 0
|
6 |
+
*
|
7 |
+
* @package Inpsyde\SearchReplace\Service
|
8 |
+
*/
|
9 |
+
class MaxExecutionTime {
|
10 |
+
|
11 |
+
/**
|
12 |
+
* @var int
|
13 |
+
*/
|
14 |
+
private $met;
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Store current timelimit and set a limit
|
18 |
+
*
|
19 |
+
* @param int $time
|
20 |
+
*/
|
21 |
+
public function set( $time = 0 ) {
|
22 |
+
|
23 |
+
if ( 0 === $time ) {
|
24 |
+
$this->store();
|
25 |
+
}
|
26 |
+
|
27 |
+
@set_time_limit( $time );
|
28 |
+
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Restore timelimit.
|
33 |
+
*/
|
34 |
+
public function restore() {
|
35 |
+
|
36 |
+
$this->set( $this->met );
|
37 |
+
|
38 |
+
}
|
39 |
+
|
40 |
+
/**
|
41 |
+
* Fetch the max_execution_time from php.ini.
|
42 |
+
*/
|
43 |
+
public function store() {
|
44 |
+
|
45 |
+
$this->met = (int) ini_get( 'max_execution_time' );
|
46 |
+
|
47 |
+
}
|
48 |
+
|
49 |
+
}
|
inc/templates/credits.php
CHANGED
@@ -1,138 +1,138 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Template for displaying sql export page
|
4 |
-
*/
|
5 |
-
|
6 |
-
// Prevent direct access.
|
7 |
-
if ( ! defined( 'SEARCH_REPLACE_BASEDIR' ) ) {
|
8 |
-
echo "Hi there! I'm just a part of plugin, not much I can do when called directly.";
|
9 |
-
exit;
|
10 |
-
}
|
11 |
-
?>
|
12 |
-
|
13 |
-
<h2><?php esc_html_e( 'Hey nice to have you here!', 'search-and-replace' ); ?></h2>
|
14 |
-
<p>
|
15 |
-
<?php printf(
|
16 |
-
wp_kses(
|
17 |
-
__(
|
18 |
-
'Search and Replace is refactored in 2015 by <a href="%1$s">Inpsyde GmbH</a>, maintained since 2006 and based on the original from <a href="%2$s">Mark Cunningham</a>.',
|
19 |
-
'search-and-replace'
|
20 |
-
),
|
21 |
-
[
|
22 |
-
'a' => [
|
23 |
-
'href' => true,
|
24 |
-
],
|
25 |
-
]
|
26 |
-
),
|
27 |
-
'http://inpsyde.com/',
|
28 |
-
'http://thedeadone.net'
|
29 |
-
);
|
30 |
-
?>
|
31 |
-
</p>
|
32 |
-
|
33 |
-
<h2><?php esc_html_e( 'You rock! contribute the plugin.', 'search-and-replace' ); ?></h2>
|
34 |
-
<p>
|
35 |
-
<?php printf(
|
36 |
-
wp_kses(
|
37 |
-
__(
|
38 |
-
'You can contribute the Plugin go to the repository on <a href="%s">github</a> making changes, creating issues, or submitting changes.',
|
39 |
-
'search-and-replace'
|
40 |
-
),
|
41 |
-
[
|
42 |
-
'a' => [
|
43 |
-
'href' => true,
|
44 |
-
],
|
45 |
-
]
|
46 |
-
),
|
47 |
-
'https://github.com/inpsyde/search-and-replace/'
|
48 |
-
);
|
49 |
-
?>
|
50 |
-
</p>
|
51 |
-
|
52 |
-
<h2><?php esc_html_e( 'We are Inpsyde', 'search-and-replace' ); ?></h2>
|
53 |
-
<p>
|
54 |
-
<?php esc_html_e(
|
55 |
-
'Inpsyde has developed enterprise solutions with the world’s most popular open-source CMS ever since it was a kitten. We still do, inconvincibly convinced.',
|
56 |
-
'search-and-replace'
|
57 |
-
);
|
58 |
-
?>
|
59 |
-
</p>
|
60 |
-
<p>
|
61 |
-
<?php printf(
|
62 |
-
wp_kses(
|
63 |
-
__(
|
64 |
-
'Inpsyde is a WordPress <a href="%1$s">VIP Service Partner</a> and <a href="%2$s">WooCommerce Expert</a>.',
|
65 |
-
'search-and-replace'
|
66 |
-
),
|
67 |
-
[
|
68 |
-
'a' => [
|
69 |
-
'href' => true,
|
70 |
-
],
|
71 |
-
]
|
72 |
-
),
|
73 |
-
'https://vip.wordpress.com/partner/inpsyde/',
|
74 |
-
'https://www.woothemes.com/experts/inpsyde-gmbh/'
|
75 |
-
);
|
76 |
-
?>
|
77 |
-
</p>
|
78 |
-
<p>
|
79 |
-
<?php printf(
|
80 |
-
wp_kses(
|
81 |
-
__( 'Look at our other <a href="%s">free WordPress plugins</a>.', 'search-and-replace' ),
|
82 |
-
[
|
83 |
-
'a' => [
|
84 |
-
'href' => true,
|
85 |
-
],
|
86 |
-
]
|
87 |
-
),
|
88 |
-
esc_url( 'https://profiles.wordpress.org/inpsyde/#content-plugins' )
|
89 |
-
);
|
90 |
-
?>
|
91 |
-
</p>
|
92 |
-
|
93 |
-
|
94 |
-
<h2><?php esc_html_e( 'Working at Inpsyde', 'search-and-replace' ); ?></h2>
|
95 |
-
<p>
|
96 |
-
<?php esc_html_e(
|
97 |
-
'As the biggest WordPress enterprise in Europe, we’re dynamically growing and constantly looking for new employees. So, do you want to shape WordPress in an interesting and exciting work environment? Here we are!',
|
98 |
-
'search-and-replace'
|
99 |
-
);
|
100 |
-
?>
|
101 |
-
</p>
|
102 |
-
<p>
|
103 |
-
<?php esc_html_e(
|
104 |
-
'At the moment we’re looking for developers for WordPress based products and services. If you’re not a developer and want to be part of us, we’d be happy to recieve your unsolicited application. At Inpsyde you can expect an open, modern and lively company culture:',
|
105 |
-
'search-and-replace'
|
106 |
-
);
|
107 |
-
?>
|
108 |
-
</p>
|
109 |
-
<ol>
|
110 |
-
<li><?php esc_html_e( 'challenging and exciting projects', 'search-and-replace' ); ?></li>
|
111 |
-
<li><?php esc_html_e( 'flexible working hours in remote office', 'search-and-replace' ); ?></li>
|
112 |
-
<li><?php esc_html_e( 'deliberately flat hierarchies and short decision paths', 'search-and-replace' ); ?></li>
|
113 |
-
<li><?php esc_html_e( 'a wide variety of tasks', 'search-and-replace' ); ?></li>
|
114 |
-
<li><?php esc_html_e(
|
115 |
-
'freedom for personal development and responsible, self-reliant action',
|
116 |
-
'search-and-replace'
|
117 |
-
); ?>
|
118 |
-
</li>
|
119 |
-
|
120 |
-
</ol>
|
121 |
-
<p>
|
122 |
-
<?php printf(
|
123 |
-
wp_kses(
|
124 |
-
/* translators: $1 is a url */
|
125 |
-
__(
|
126 |
-
'If you love open source and especially WordPress, if you love to organize your working days by yourself, and you want to use your pragmatic problem-solving skills and result-oriented work methods: <a href="%s">join our team</a>!',
|
127 |
-
'search-and-replace'
|
128 |
-
),
|
129 |
-
[
|
130 |
-
'a' => [
|
131 |
-
'href' => true,
|
132 |
-
],
|
133 |
-
]
|
134 |
-
),
|
135 |
-
'http://inpsyde.com/#jobs'
|
136 |
-
);
|
137 |
-
?>
|
138 |
-
</p>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Template for displaying sql export page
|
4 |
+
*/
|
5 |
+
|
6 |
+
// Prevent direct access.
|
7 |
+
if ( ! defined( 'SEARCH_REPLACE_BASEDIR' ) ) {
|
8 |
+
echo "Hi there! I'm just a part of plugin, not much I can do when called directly.";
|
9 |
+
exit;
|
10 |
+
}
|
11 |
+
?>
|
12 |
+
|
13 |
+
<h2><?php esc_html_e( 'Hey nice to have you here!', 'search-and-replace' ); ?></h2>
|
14 |
+
<p>
|
15 |
+
<?php printf(
|
16 |
+
wp_kses(
|
17 |
+
__(
|
18 |
+
'Search and Replace is refactored in 2015 by <a href="%1$s">Inpsyde GmbH</a>, maintained since 2006 and based on the original from <a href="%2$s">Mark Cunningham</a>.',
|
19 |
+
'search-and-replace'
|
20 |
+
),
|
21 |
+
[
|
22 |
+
'a' => [
|
23 |
+
'href' => true,
|
24 |
+
],
|
25 |
+
]
|
26 |
+
),
|
27 |
+
'http://inpsyde.com/',
|
28 |
+
'http://thedeadone.net'
|
29 |
+
);
|
30 |
+
?>
|
31 |
+
</p>
|
32 |
+
|
33 |
+
<h2><?php esc_html_e( 'You rock! contribute the plugin.', 'search-and-replace' ); ?></h2>
|
34 |
+
<p>
|
35 |
+
<?php printf(
|
36 |
+
wp_kses(
|
37 |
+
__(
|
38 |
+
'You can contribute the Plugin go to the repository on <a href="%s">github</a> making changes, creating issues, or submitting changes.',
|
39 |
+
'search-and-replace'
|
40 |
+
),
|
41 |
+
[
|
42 |
+
'a' => [
|
43 |
+
'href' => true,
|
44 |
+
],
|
45 |
+
]
|
46 |
+
),
|
47 |
+
'https://github.com/inpsyde/search-and-replace/'
|
48 |
+
);
|
49 |
+
?>
|
50 |
+
</p>
|
51 |
+
|
52 |
+
<h2><?php esc_html_e( 'We are Inpsyde', 'search-and-replace' ); ?></h2>
|
53 |
+
<p>
|
54 |
+
<?php esc_html_e(
|
55 |
+
'Inpsyde has developed enterprise solutions with the world’s most popular open-source CMS ever since it was a kitten. We still do, inconvincibly convinced.',
|
56 |
+
'search-and-replace'
|
57 |
+
);
|
58 |
+
?>
|
59 |
+
</p>
|
60 |
+
<p>
|
61 |
+
<?php printf(
|
62 |
+
wp_kses(
|
63 |
+
__(
|
64 |
+
'Inpsyde is a WordPress <a href="%1$s">VIP Service Partner</a> and <a href="%2$s">WooCommerce Expert</a>.',
|
65 |
+
'search-and-replace'
|
66 |
+
),
|
67 |
+
[
|
68 |
+
'a' => [
|
69 |
+
'href' => true,
|
70 |
+
],
|
71 |
+
]
|
72 |
+
),
|
73 |
+
'https://vip.wordpress.com/partner/inpsyde/',
|
74 |
+
'https://www.woothemes.com/experts/inpsyde-gmbh/'
|
75 |
+
);
|
76 |
+
?>
|
77 |
+
</p>
|
78 |
+
<p>
|
79 |
+
<?php printf(
|
80 |
+
wp_kses(
|
81 |
+
__( 'Look at our other <a href="%s">free WordPress plugins</a>.', 'search-and-replace' ),
|
82 |
+
[
|
83 |
+
'a' => [
|
84 |
+
'href' => true,
|
85 |
+
],
|
86 |
+
]
|
87 |
+
),
|
88 |
+
esc_url( 'https://profiles.wordpress.org/inpsyde/#content-plugins' )
|
89 |
+
);
|
90 |
+
?>
|
91 |
+
</p>
|
92 |
+
|
93 |
+
|
94 |
+
<h2><?php esc_html_e( 'Working at Inpsyde', 'search-and-replace' ); ?></h2>
|
95 |
+
<p>
|
96 |
+
<?php esc_html_e(
|
97 |
+
'As the biggest WordPress enterprise in Europe, we’re dynamically growing and constantly looking for new employees. So, do you want to shape WordPress in an interesting and exciting work environment? Here we are!',
|
98 |
+
'search-and-replace'
|
99 |
+
);
|
100 |
+
?>
|
101 |
+
</p>
|
102 |
+
<p>
|
103 |
+
<?php esc_html_e(
|
104 |
+
'At the moment we’re looking for developers for WordPress based products and services. If you’re not a developer and want to be part of us, we’d be happy to recieve your unsolicited application. At Inpsyde you can expect an open, modern and lively company culture:',
|
105 |
+
'search-and-replace'
|
106 |
+
);
|
107 |
+
?>
|
108 |
+
</p>
|
109 |
+
<ol>
|
110 |
+
<li><?php esc_html_e( 'challenging and exciting projects', 'search-and-replace' ); ?></li>
|
111 |
+
<li><?php esc_html_e( 'flexible working hours in remote office', 'search-and-replace' ); ?></li>
|
112 |
+
<li><?php esc_html_e( 'deliberately flat hierarchies and short decision paths', 'search-and-replace' ); ?></li>
|
113 |
+
<li><?php esc_html_e( 'a wide variety of tasks', 'search-and-replace' ); ?></li>
|
114 |
+
<li><?php esc_html_e(
|
115 |
+
'freedom for personal development and responsible, self-reliant action',
|
116 |
+
'search-and-replace'
|
117 |
+
); ?>
|
118 |
+
</li>
|
119 |
+
|
120 |
+
</ol>
|
121 |
+
<p>
|
122 |
+
<?php printf(
|
123 |
+
wp_kses(
|
124 |
+
/* translators: $1 is a url */
|
125 |
+
__(
|
126 |
+
'If you love open source and especially WordPress, if you love to organize your working days by yourself, and you want to use your pragmatic problem-solving skills and result-oriented work methods: <a href="%s">join our team</a>!',
|
127 |
+
'search-and-replace'
|
128 |
+
),
|
129 |
+
[
|
130 |
+
'a' => [
|
131 |
+
'href' => true,
|
132 |
+
],
|
133 |
+
]
|
134 |
+
),
|
135 |
+
'http://inpsyde.com/#jobs'
|
136 |
+
);
|
137 |
+
?>
|
138 |
+
</p>
|
inc/templates/db-backup.php
CHANGED
@@ -1,22 +1,22 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Template for displaying sql export page
|
4 |
-
*/
|
5 |
-
|
6 |
-
// Prevent direct access.
|
7 |
-
if ( ! defined( 'SEARCH_REPLACE_BASEDIR' ) ) {
|
8 |
-
echo "Hi there! I'm just a part of plugin, not much I can do when called directly.";
|
9 |
-
exit;
|
10 |
-
}
|
11 |
-
?>
|
12 |
-
|
13 |
-
<p>
|
14 |
-
<?php esc_html_e(
|
15 |
-
'Create a backup of your database by clicking "Create SQL File".',
|
16 |
-
'search-and-replace'
|
17 |
-
); ?>
|
18 |
-
</p>
|
19 |
-
|
20 |
-
<form action="" method="post">
|
21 |
-
<?php $this->show_submit_button(); ?>
|
22 |
-
</form>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Template for displaying sql export page
|
4 |
+
*/
|
5 |
+
|
6 |
+
// Prevent direct access.
|
7 |
+
if ( ! defined( 'SEARCH_REPLACE_BASEDIR' ) ) {
|
8 |
+
echo "Hi there! I'm just a part of plugin, not much I can do when called directly.";
|
9 |
+
exit;
|
10 |
+
}
|
11 |
+
?>
|
12 |
+
|
13 |
+
<p>
|
14 |
+
<?php esc_html_e(
|
15 |
+
'Create a backup of your database by clicking "Create SQL File".',
|
16 |
+
'search-and-replace'
|
17 |
+
); ?>
|
18 |
+
</p>
|
19 |
+
|
20 |
+
<form action="" method="post">
|
21 |
+
<?php $this->show_submit_button(); ?>
|
22 |
+
</form>
|
inc/templates/replace-domain.php
CHANGED
@@ -1,93 +1,93 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Template for displaying replace domain page
|
4 |
-
*/
|
5 |
-
|
6 |
-
// Prevent direct access.
|
7 |
-
if ( ! defined( 'SEARCH_REPLACE_BASEDIR' ) ) {
|
8 |
-
echo "Hi there! I'm just a part of plugin, not much I can do when called directly.";
|
9 |
-
exit;
|
10 |
-
}
|
11 |
-
?>
|
12 |
-
<p>
|
13 |
-
<?php esc_html_e(
|
14 |
-
'If you want to migrate your site to another domain, enter the new URL in the field "Replace with" and click "Do Replace Domain/Url". You can then download a database backup containing the new URL.',
|
15 |
-
'search-and-replace'
|
16 |
-
); ?>
|
17 |
-
</p>
|
18 |
-
|
19 |
-
<form action="" method="post">
|
20 |
-
|
21 |
-
<table class="form-table">
|
22 |
-
<tbody>
|
23 |
-
|
24 |
-
<tr>
|
25 |
-
<th>
|
26 |
-
<label for="search">
|
27 |
-
<?php esc_html_e( 'Search for: ', 'search-and-replace' ); ?>
|
28 |
-
</label>
|
29 |
-
</th>
|
30 |
-
<td>
|
31 |
-
<input id="search" type="text" name="search" value="<?php esc_url( get_site_url() ); ?>" />
|
32 |
-
</td>
|
33 |
-
</tr>
|
34 |
-
|
35 |
-
<tr>
|
36 |
-
<th>
|
37 |
-
<label for="replace">
|
38 |
-
<?php esc_html_e( 'Replace with: ', 'search-and-replace' ); ?>
|
39 |
-
</label>
|
40 |
-
</th>
|
41 |
-
<td>
|
42 |
-
<input
|
43 |
-
id="replace"
|
44 |
-
type="text"
|
45 |
-
name="replace"
|
46 |
-
placeholder="<?php esc_attr_e( 'New URL', 'search-and-replace' ); ?>"
|
47 |
-
/>
|
48 |
-
</td>
|
49 |
-
</tr>
|
50 |
-
|
51 |
-
<tr>
|
52 |
-
<th>
|
53 |
-
<label for="change_db_prefix">
|
54 |
-
<?php esc_html_e( 'Change database prefix', 'search-and-replace' ); ?>
|
55 |
-
</label>
|
56 |
-
</th>
|
57 |
-
<td><input id="change_db_prefix" type="checkbox" name="change_db_prefix" /></td>
|
58 |
-
</tr>
|
59 |
-
|
60 |
-
<tr class="disabled">
|
61 |
-
<th>
|
62 |
-
<label for="current_db_prefix">
|
63 |
-
<?php esc_html_e( 'Current prefix: ', 'search-and-replace' ); ?>
|
64 |
-
</label>
|
65 |
-
</th>
|
66 |
-
<td>
|
67 |
-
<?php echo esc_html( $this->dbm->get_base_prefix() ); ?>
|
68 |
-
</td>
|
69 |
-
</tr>
|
70 |
-
|
71 |
-
<tr class="maybe_disabled disabled">
|
72 |
-
<th>
|
73 |
-
<label for="new_db_prefix">
|
74 |
-
<?php esc_html_e( 'New prefix: ', 'search-and-replace' ); ?>
|
75 |
-
</label>
|
76 |
-
</th>
|
77 |
-
<td>
|
78 |
-
<input
|
79 |
-
id="new_db_prefix"
|
80 |
-
type="text"
|
81 |
-
name="new_db_prefix"
|
82 |
-
disabled
|
83 |
-
placeholder="<?php esc_attr_e( 'E.g new_', 'search-and-replace' ); ?>"
|
84 |
-
/>
|
85 |
-
<p>
|
86 |
-
<?php esc_html_e( 'Underscore suffix "_" can be omitted', 'search-and-replace' ); ?>
|
87 |
-
</p>
|
88 |
-
</td>
|
89 |
-
</tr>
|
90 |
-
</tbody>
|
91 |
-
</table>
|
92 |
-
<?php $this->show_submit_button(); ?>
|
93 |
-
</form>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Template for displaying replace domain page
|
4 |
+
*/
|
5 |
+
|
6 |
+
// Prevent direct access.
|
7 |
+
if ( ! defined( 'SEARCH_REPLACE_BASEDIR' ) ) {
|
8 |
+
echo "Hi there! I'm just a part of plugin, not much I can do when called directly.";
|
9 |
+
exit;
|
10 |
+
}
|
11 |
+
?>
|
12 |
+
<p>
|
13 |
+
<?php esc_html_e(
|
14 |
+
'If you want to migrate your site to another domain, enter the new URL in the field "Replace with" and click "Do Replace Domain/Url". You can then download a database backup containing the new URL.',
|
15 |
+
'search-and-replace'
|
16 |
+
); ?>
|
17 |
+
</p>
|
18 |
+
|
19 |
+
<form action="" method="post">
|
20 |
+
|
21 |
+
<table class="form-table">
|
22 |
+
<tbody>
|
23 |
+
|
24 |
+
<tr>
|
25 |
+
<th>
|
26 |
+
<label for="search">
|
27 |
+
<?php esc_html_e( 'Search for: ', 'search-and-replace' ); ?>
|
28 |
+
</label>
|
29 |
+
</th>
|
30 |
+
<td>
|
31 |
+
<input id="search" type="text" name="search" value="<?php esc_url( get_site_url() ); ?>" />
|
32 |
+
</td>
|
33 |
+
</tr>
|
34 |
+
|
35 |
+
<tr>
|
36 |
+
<th>
|
37 |
+
<label for="replace">
|
38 |
+
<?php esc_html_e( 'Replace with: ', 'search-and-replace' ); ?>
|
39 |
+
</label>
|
40 |
+
</th>
|
41 |
+
<td>
|
42 |
+
<input
|
43 |
+
id="replace"
|
44 |
+
type="text"
|
45 |
+
name="replace"
|
46 |
+
placeholder="<?php esc_attr_e( 'New URL', 'search-and-replace' ); ?>"
|
47 |
+
/>
|
48 |
+
</td>
|
49 |
+
</tr>
|
50 |
+
|
51 |
+
<tr>
|
52 |
+
<th>
|
53 |
+
<label for="change_db_prefix">
|
54 |
+
<?php esc_html_e( 'Change database prefix', 'search-and-replace' ); ?>
|
55 |
+
</label>
|
56 |
+
</th>
|
57 |
+
<td><input id="change_db_prefix" type="checkbox" name="change_db_prefix" /></td>
|
58 |
+
</tr>
|
59 |
+
|
60 |
+
<tr class="disabled">
|
61 |
+
<th>
|
62 |
+
<label for="current_db_prefix">
|
63 |
+
<?php esc_html_e( 'Current prefix: ', 'search-and-replace' ); ?>
|
64 |
+
</label>
|
65 |
+
</th>
|
66 |
+
<td>
|
67 |
+
<?php echo esc_html( $this->dbm->get_base_prefix() ); ?>
|
68 |
+
</td>
|
69 |
+
</tr>
|
70 |
+
|
71 |
+
<tr class="maybe_disabled disabled">
|
72 |
+
<th>
|
73 |
+
<label for="new_db_prefix">
|
74 |
+
<?php esc_html_e( 'New prefix: ', 'search-and-replace' ); ?>
|
75 |
+
</label>
|
76 |
+
</th>
|
77 |
+
<td>
|
78 |
+
<input
|
79 |
+
id="new_db_prefix"
|
80 |
+
type="text"
|
81 |
+
name="new_db_prefix"
|
82 |
+
disabled
|
83 |
+
placeholder="<?php esc_attr_e( 'E.g new_', 'search-and-replace' ); ?>"
|
84 |
+
/>
|
85 |
+
<p>
|
86 |
+
<?php esc_html_e( 'Underscore suffix "_" can be omitted', 'search-and-replace' ); ?>
|
87 |
+
</p>
|
88 |
+
</td>
|
89 |
+
</tr>
|
90 |
+
</tbody>
|
91 |
+
</table>
|
92 |
+
<?php $this->show_submit_button(); ?>
|
93 |
+
</form>
|
inc/templates/search-replace.php
CHANGED
@@ -1,110 +1,110 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Template for displaying search & replace page
|
4 |
-
*/
|
5 |
-
|
6 |
-
// Prevent direct access.
|
7 |
-
if ( ! defined( 'SEARCH_REPLACE_BASEDIR' ) ) {
|
8 |
-
echo "Hi there! I'm just a part of plugin, not much I can do when called directly.";
|
9 |
-
exit;
|
10 |
-
}
|
11 |
-
?>
|
12 |
-
<form action="" method="post">
|
13 |
-
<table class="form-table">
|
14 |
-
<tbody>
|
15 |
-
<tr>
|
16 |
-
<th>
|
17 |
-
<label for="search">
|
18 |
-
<?php esc_html_e( 'Search for: ', 'search-and-replace' ); ?>
|
19 |
-
</label>
|
20 |
-
</th>
|
21 |
-
<td>
|
22 |
-
<textarea id="search" type="text" name="search" rows="1"><?php $this->get_search_value() ?></textarea>
|
23 |
-
</td>
|
24 |
-
</tr>
|
25 |
-
<tr>
|
26 |
-
<th>
|
27 |
-
<label for="replace">
|
28 |
-
<?php esc_html_e( 'Replace with: ', 'search-and-replace' ); ?>
|
29 |
-
</label>
|
30 |
-
</th>
|
31 |
-
<td>
|
32 |
-
<input id="replace" type="text" name="replace" value="<?php $this->get_replace_value() ?>" />
|
33 |
-
</td>
|
34 |
-
</tr>
|
35 |
-
<tr>
|
36 |
-
<th>
|
37 |
-
<label for="csv">
|
38 |
-
<?php esc_html_e( 'CSV Format Search/Replace:', 'search-and-replace' ); ?>
|
39 |
-
</label>
|
40 |
-
</th>
|
41 |
-
<td>
|
42 |
-
<textarea id="csv" cols="46" rows="5" name="csv" placeholder="<?php esc_html_e(
|
43 |
-
'search value, replace value (one per line)',
|
44 |
-
'search-and-replace'
|
45 |
-
); ?>"><?php $this->get_csv_value(); ?></textarea>
|
46 |
-
<p id="csv-hint">
|
47 |
-
<?php esc_html_e(
|
48 |
-
'Using comma delimited( , ). For example to replace cat with dog: cat,dog',
|
49 |
-
'search-and-replace'
|
50 |
-
); ?>
|
51 |
-
</p>
|
52 |
-
</td>
|
53 |
-
</tr>
|
54 |
-
<tr>
|
55 |
-
<th><strong><?php esc_html_e( 'Select tables', 'search-and-replace' ); ?></strong></th>
|
56 |
-
<td>
|
57 |
-
<?php $this->show_table_list(); ?>
|
58 |
-
<p>
|
59 |
-
<input id="select_all_tables" type="checkbox" name="select_all" />
|
60 |
-
<label for="select_all_tables">
|
61 |
-
<?php esc_html_e( 'Select all tables', 'search-and-replace' ); ?>
|
62 |
-
</label>
|
63 |
-
</p>
|
64 |
-
</td>
|
65 |
-
</tr>
|
66 |
-
|
67 |
-
<tr>
|
68 |
-
<th>
|
69 |
-
<label for="dry_run">
|
70 |
-
<?php esc_html_e( 'Dry Run', 'search-and-replace' ); ?>
|
71 |
-
</label>
|
72 |
-
</th>
|
73 |
-
<td>
|
74 |
-
<input type="checkbox" id="dry_run" name="dry_run" checked />
|
75 |
-
</td>
|
76 |
-
</tr>
|
77 |
-
<tr class="maybe_disabled disabled">
|
78 |
-
<th>
|
79 |
-
<?php esc_html_e( 'Export SQL file or write changes to DB?', 'search-and-replace' ); ?>
|
80 |
-
</th>
|
81 |
-
<td>
|
82 |
-
<p>
|
83 |
-
<input id="radio1" type="radio" name="export_or_save" value="export" checked disabled />
|
84 |
-
<label for="radio1">
|
85 |
-
<?php esc_html_e( 'Export SQL file with changes', 'search-and-replace' ); ?>
|
86 |
-
</label>
|
87 |
-
</p>
|
88 |
-
<p>
|
89 |
-
<input id="radio2" type="radio" name="export_or_save" value="save_to_db" disabled />
|
90 |
-
<label for="radio2">
|
91 |
-
<?php esc_html_e( 'Save changes to Database', 'search-and-replace' ); ?>
|
92 |
-
</label>
|
93 |
-
</p>
|
94 |
-
</td>
|
95 |
-
</tr>
|
96 |
-
<tr class="maybe_disabled disabled">
|
97 |
-
<th>
|
98 |
-
<label for="compress">
|
99 |
-
<?php esc_html_e( 'Use GZ compression', 'search-and-replace' ); ?>
|
100 |
-
</label>
|
101 |
-
</th>
|
102 |
-
<td>
|
103 |
-
<input id="compress" type="checkbox" name="compress" disabled />
|
104 |
-
</td>
|
105 |
-
</tr>
|
106 |
-
|
107 |
-
</tbody>
|
108 |
-
</table>
|
109 |
-
<?php $this->show_submit_button( 'search-submit' ); ?>
|
110 |
-
</form>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Template for displaying search & replace page
|
4 |
+
*/
|
5 |
+
|
6 |
+
// Prevent direct access.
|
7 |
+
if ( ! defined( 'SEARCH_REPLACE_BASEDIR' ) ) {
|
8 |
+
echo "Hi there! I'm just a part of plugin, not much I can do when called directly.";
|
9 |
+
exit;
|
10 |
+
}
|
11 |
+
?>
|
12 |
+
<form action="" method="post">
|
13 |
+
<table class="form-table">
|
14 |
+
<tbody>
|
15 |
+
<tr>
|
16 |
+
<th>
|
17 |
+
<label for="search">
|
18 |
+
<?php esc_html_e( 'Search for: ', 'search-and-replace' ); ?>
|
19 |
+
</label>
|
20 |
+
</th>
|
21 |
+
<td>
|
22 |
+
<textarea id="search" type="text" name="search" rows="1"><?php $this->get_search_value() ?></textarea>
|
23 |
+
</td>
|
24 |
+
</tr>
|
25 |
+
<tr>
|
26 |
+
<th>
|
27 |
+
<label for="replace">
|
28 |
+
<?php esc_html_e( 'Replace with: ', 'search-and-replace' ); ?>
|
29 |
+
</label>
|
30 |
+
</th>
|
31 |
+
<td>
|
32 |
+
<input id="replace" type="text" name="replace" value="<?php $this->get_replace_value() ?>" />
|
33 |
+
</td>
|
34 |
+
</tr>
|
35 |
+
<tr>
|
36 |
+
<th>
|
37 |
+
<label for="csv">
|
38 |
+
<?php esc_html_e( 'CSV Format Search/Replace:', 'search-and-replace' ); ?>
|
39 |
+
</label>
|
40 |
+
</th>
|
41 |
+
<td>
|
42 |
+
<textarea id="csv" cols="46" rows="5" name="csv" placeholder="<?php esc_html_e(
|
43 |
+
'search value, replace value (one per line)',
|
44 |
+
'search-and-replace'
|
45 |
+
); ?>"><?php $this->get_csv_value(); ?></textarea>
|
46 |
+
<p id="csv-hint">
|
47 |
+
<?php esc_html_e(
|
48 |
+
'Using comma delimited( , ). For example to replace cat with dog: cat,dog',
|
49 |
+
'search-and-replace'
|
50 |
+
); ?>
|
51 |
+
</p>
|
52 |
+
</td>
|
53 |
+
</tr>
|
54 |
+
<tr>
|
55 |
+
<th><strong><?php esc_html_e( 'Select tables', 'search-and-replace' ); ?></strong></th>
|
56 |
+
<td>
|
57 |
+
<?php $this->show_table_list(); ?>
|
58 |
+
<p>
|
59 |
+
<input id="select_all_tables" type="checkbox" name="select_all" />
|
60 |
+
<label for="select_all_tables">
|
61 |
+
<?php esc_html_e( 'Select all tables', 'search-and-replace' ); ?>
|
62 |
+
</label>
|
63 |
+
</p>
|
64 |
+
</td>
|
65 |
+
</tr>
|
66 |
+
|
67 |
+
<tr>
|
68 |
+
<th>
|
69 |
+
<label for="dry_run">
|
70 |
+
<?php esc_html_e( 'Dry Run', 'search-and-replace' ); ?>
|
71 |
+
</label>
|
72 |
+
</th>
|
73 |
+
<td>
|
74 |
+
<input type="checkbox" id="dry_run" name="dry_run" checked />
|
75 |
+
</td>
|
76 |
+
</tr>
|
77 |
+
<tr class="maybe_disabled disabled">
|
78 |
+
<th>
|
79 |
+
<?php esc_html_e( 'Export SQL file or write changes to DB?', 'search-and-replace' ); ?>
|
80 |
+
</th>
|
81 |
+
<td>
|
82 |
+
<p>
|
83 |
+
<input id="radio1" type="radio" name="export_or_save" value="export" checked disabled />
|
84 |
+
<label for="radio1">
|
85 |
+
<?php esc_html_e( 'Export SQL file with changes', 'search-and-replace' ); ?>
|
86 |
+
</label>
|
87 |
+
</p>
|
88 |
+
<p>
|
89 |
+
<input id="radio2" type="radio" name="export_or_save" value="save_to_db" disabled />
|
90 |
+
<label for="radio2">
|
91 |
+
<?php esc_html_e( 'Save changes to Database', 'search-and-replace' ); ?>
|
92 |
+
</label>
|
93 |
+
</p>
|
94 |
+
</td>
|
95 |
+
</tr>
|
96 |
+
<tr class="maybe_disabled disabled">
|
97 |
+
<th>
|
98 |
+
<label for="compress">
|
99 |
+
<?php esc_html_e( 'Use GZ compression', 'search-and-replace' ); ?>
|
100 |
+
</label>
|
101 |
+
</th>
|
102 |
+
<td>
|
103 |
+
<input id="compress" type="checkbox" name="compress" disabled />
|
104 |
+
</td>
|
105 |
+
</tr>
|
106 |
+
|
107 |
+
</tbody>
|
108 |
+
</table>
|
109 |
+
<?php $this->show_submit_button( 'search-submit' ); ?>
|
110 |
+
</form>
|
inc/templates/sql-import.php
CHANGED
@@ -1,35 +1,35 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Template for displaying sql import page
|
4 |
-
*/
|
5 |
-
|
6 |
-
// Prevent direct access.
|
7 |
-
if ( ! defined( 'SEARCH_REPLACE_BASEDIR' ) ) {
|
8 |
-
echo "Hi there! I'm just a part of plugin, not much I can do when called directly.";
|
9 |
-
exit;
|
10 |
-
}
|
11 |
-
?>
|
12 |
-
|
13 |
-
<form action="" method="post" enctype="multipart/form-data">
|
14 |
-
<table class="form-table">
|
15 |
-
<tbody>
|
16 |
-
<tr>
|
17 |
-
<th>
|
18 |
-
<strong>
|
19 |
-
<?php esc_html_e( 'Select SQL file to upload. ', 'search-and-replace' ); ?>
|
20 |
-
</strong>
|
21 |
-
</th>
|
22 |
-
|
23 |
-
<td><input type="file" name="file_to_upload" id="file_to_upload"></td>
|
24 |
-
</tr>
|
25 |
-
<tr>
|
26 |
-
<th></th>
|
27 |
-
<td>
|
28 |
-
<?php esc_html_e( 'Maximum file size: ', 'search-and-replace' ); ?>
|
29 |
-
<?php echo floatval( $this->file_upload_max_size() ) . 'KB'; ?>
|
30 |
-
</td>
|
31 |
-
</tr>
|
32 |
-
</tbody>
|
33 |
-
</table>
|
34 |
-
<?php $this->show_submit_button(); ?>
|
35 |
-
</form>
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Template for displaying sql import page
|
4 |
+
*/
|
5 |
+
|
6 |
+
// Prevent direct access.
|
7 |
+
if ( ! defined( 'SEARCH_REPLACE_BASEDIR' ) ) {
|
8 |
+
echo "Hi there! I'm just a part of plugin, not much I can do when called directly.";
|
9 |
+
exit;
|
10 |
+
}
|
11 |
+
?>
|
12 |
+
|
13 |
+
<form action="" method="post" enctype="multipart/form-data">
|
14 |
+
<table class="form-table">
|
15 |
+
<tbody>
|
16 |
+
<tr>
|
17 |
+
<th>
|
18 |
+
<strong>
|
19 |
+
<?php esc_html_e( 'Select SQL file to upload. ', 'search-and-replace' ); ?>
|
20 |
+
</strong>
|
21 |
+
</th>
|
22 |
+
|
23 |
+
<td><input type="file" name="file_to_upload" id="file_to_upload"></td>
|
24 |
+
</tr>
|
25 |
+
<tr>
|
26 |
+
<th></th>
|
27 |
+
<td>
|
28 |
+
<?php esc_html_e( 'Maximum file size: ', 'search-and-replace' ); ?>
|
29 |
+
<?php echo floatval( $this->file_upload_max_size() ) . 'KB'; ?>
|
30 |
+
</td>
|
31 |
+
</tr>
|
32 |
+
</tbody>
|
33 |
+
</table>
|
34 |
+
<?php $this->show_submit_button(); ?>
|
35 |
+
</form>
|
inpsyde-search-replace.php
CHANGED
@@ -1,129 +1,129 @@
|
|
1 |
-
<?php # -*- coding: utf-8 -*-
|
2 |
-
|
3 |
-
/**
|
4 |
-
* Plugin Name: Search & Replace
|
5 |
-
* Plugin URI: https://wordpress.org/plugins/search-and-replace/
|
6 |
-
* Description: Search & Replace data in your whole WordPress setup, backup and import your database, change table prefix or migrate your domain to another domain.
|
7 |
-
* Author: Inpsyde GmbH
|
8 |
-
* URI: https://inpsyde.com
|
9 |
-
* Contributors: s-hinse, derpixler, ChriCo, Bueltge, inpsyde
|
10 |
-
* Version: 3.2.
|
11 |
-
* Text Domain: search-and-replace
|
12 |
-
* Domain Path: /languages
|
13 |
-
* License:
|
14 |
-
* License URI:
|
15 |
-
*/
|
16 |
-
|
17 |
-
use Inpsyde\SearchReplace\Database;
|
18 |
-
use Inpsyde\SearchReplace\Page;
|
19 |
-
|
20 |
-
defined( 'ABSPATH' ) || die( 'No direct access!' );
|
21 |
-
|
22 |
-
add_action( 'plugins_loaded', 'search_replace_load' );
|
23 |
-
register_activation_hook( __FILE__, 'search_replace_activate' );
|
24 |
-
|
25 |
-
/**
|
26 |
-
* Validate requirements on activation
|
27 |
-
*
|
28 |
-
* Runs on plugin activation.
|
29 |
-
* Check if php min 5.6.0 if not deactivate the plugin.
|
30 |
-
*
|
31 |
-
* @since 3.1.1
|
32 |
-
*
|
33 |
-
* @return void
|
34 |
-
*/
|
35 |
-
function search_replace_activate() {
|
36 |
-
|
37 |
-
$required_php_version = '5.6.0';
|
38 |
-
$correct_php_version = version_compare( PHP_VERSION, $required_php_version, '>=' );
|
39 |
-
|
40 |
-
search_replace_textdomain();
|
41 |
-
|
42 |
-
if ( ! $correct_php_version ) {
|
43 |
-
deactivate_plugins( basename( __FILE__ ) );
|
44 |
-
|
45 |
-
wp_die(
|
46 |
-
'<p>' .
|
47 |
-
sprintf(
|
48 |
-
// translators: %1$s will replace with the PHP version of the client.
|
49 |
-
esc_attr__(
|
50 |
-
'This plugin can not be activated because it requires at least PHP version %1$s. ',
|
51 |
-
'search-and-replace'
|
52 |
-
),
|
53 |
-
$required_php_version
|
54 |
-
)
|
55 |
-
. '</p> <a href="' . admin_url( 'plugins.php' ) . '">'
|
56 |
-
. esc_attr__( 'back', 'search-and-replace' ) . '</a>'
|
57 |
-
);
|
58 |
-
|
59 |
-
}
|
60 |
-
|
61 |
-
}
|
62 |
-
|
63 |
-
/**
|
64 |
-
* Load the plugin
|
65 |
-
*
|
66 |
-
* @since 3.1.1
|
67 |
-
*
|
68 |
-
* @return bool
|
69 |
-
*/
|
70 |
-
function search_replace_load() {
|
71 |
-
|
72 |
-
global $wpdb;
|
73 |
-
|
74 |
-
// all hooks are just available on backend.
|
75 |
-
if ( ! is_admin() ) {
|
76 |
-
return false;
|
77 |
-
}
|
78 |
-
|
79 |
-
define( 'SEARCH_REPLACE_BASEDIR', plugin_dir_url( __FILE__ ) );
|
80 |
-
|
81 |
-
search_replace_textdomain();
|
82 |
-
|
83 |
-
$user_cap = apply_filters( 'search_replace_access_capability', 'manage_options' );
|
84 |
-
$file = __DIR__ . '/vendor/autoload.php';
|
85 |
-
|
86 |
-
if ( ! current_user_can( $user_cap ) || ! file_exists( $file ) ) {
|
87 |
-
return false;
|
88 |
-
}
|
89 |
-
|
90 |
-
/** @noinspection PhpIncludeInspection */
|
91 |
-
include_once $file;
|
92 |
-
|
93 |
-
$max_execution = new Inpsyde\SearchReplace\Service\MaxExecutionTime();
|
94 |
-
|
95 |
-
$dbm = new Database\Manager( $wpdb );
|
96 |
-
$replace = new Database\Replace( $dbm, $max_execution );
|
97 |
-
$dbe = new Database\Exporter( $replace, $dbm, new \WP_Error() );
|
98 |
-
$dbi = new Database\Importer( $max_execution );
|
99 |
-
|
100 |
-
$downloader = new Inpsyde\SearchReplace\FileDownloader( $dbe, $max_execution );
|
101 |
-
add_action( 'init', [ $downloader, 'deliver_backup_file' ] );
|
102 |
-
|
103 |
-
$page_manager = new Page\Manager();
|
104 |
-
$page_manager->add_page( new Page\BackupDatabase( $dbe, $downloader ) );
|
105 |
-
$page_manager->add_page( new Page\SearchReplace( $dbm, $replace, $dbe, $downloader ) );
|
106 |
-
$page_manager->add_page( new Page\ReplaceDomain( $dbm, $dbe, $downloader ) );
|
107 |
-
$page_manager->add_page( new Page\SqlImport( $dbi ) );
|
108 |
-
$page_manager->add_page( new Page\Credits() );
|
109 |
-
|
110 |
-
add_action( 'admin_menu', [ $page_manager, 'register_pages' ] );
|
111 |
-
add_action( 'admin_head', [ $page_manager, 'remove_submenu_pages' ] );
|
112 |
-
|
113 |
-
add_action( 'admin_enqueue_scripts', [ $page_manager, 'register_css' ] );
|
114 |
-
add_action( 'admin_enqueue_scripts', [ $page_manager, 'register_js' ] );
|
115 |
-
|
116 |
-
return true;
|
117 |
-
}
|
118 |
-
|
119 |
-
/**
|
120 |
-
* Loading the plugin translations.
|
121 |
-
*/
|
122 |
-
function search_replace_textdomain() {
|
123 |
-
|
124 |
-
return load_plugin_textdomain(
|
125 |
-
'search-and-replace',
|
126 |
-
false,
|
127 |
-
plugin_basename( __DIR__ ) . '/
|
128 |
-
);
|
129 |
-
}
|
1 |
+
<?php # -*- coding: utf-8 -*-
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Plugin Name: Search & Replace
|
5 |
+
* Plugin URI: https://wordpress.org/plugins/search-and-replace/
|
6 |
+
* Description: Search & Replace data in your whole WordPress setup, backup and import your database, change table prefix or migrate your domain to another domain.
|
7 |
+
* Author: Inpsyde GmbH
|
8 |
+
* URI: https://inpsyde.com
|
9 |
+
* Contributors: s-hinse, derpixler, ChriCo, Bueltge, inpsyde
|
10 |
+
* Version: 3.2.1
|
11 |
+
* Text Domain: search-and-replace
|
12 |
+
* Domain Path: /languages
|
13 |
+
* License: GPLv2+
|
14 |
+
* License URI: LICENSE
|
15 |
+
*/
|
16 |
+
|
17 |
+
use Inpsyde\SearchReplace\Database;
|
18 |
+
use Inpsyde\SearchReplace\Page;
|
19 |
+
|
20 |
+
defined( 'ABSPATH' ) || die( 'No direct access!' );
|
21 |
+
|
22 |
+
add_action( 'plugins_loaded', 'search_replace_load' );
|
23 |
+
register_activation_hook( __FILE__, 'search_replace_activate' );
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Validate requirements on activation
|
27 |
+
*
|
28 |
+
* Runs on plugin activation.
|
29 |
+
* Check if php min 5.6.0 if not deactivate the plugin.
|
30 |
+
*
|
31 |
+
* @since 3.1.1
|
32 |
+
*
|
33 |
+
* @return void
|
34 |
+
*/
|
35 |
+
function search_replace_activate() {
|
36 |
+
|
37 |
+
$required_php_version = '5.6.0';
|
38 |
+
$correct_php_version = version_compare( PHP_VERSION, $required_php_version, '>=' );
|
39 |
+
|
40 |
+
search_replace_textdomain();
|
41 |
+
|
42 |
+
if ( ! $correct_php_version ) {
|
43 |
+
deactivate_plugins( basename( __FILE__ ) );
|
44 |
+
|
45 |
+
wp_die(
|
46 |
+
'<p>' .
|
47 |
+
sprintf(
|
48 |
+
// translators: %1$s will replace with the PHP version of the client.
|
49 |
+
esc_attr__(
|
50 |
+
'This plugin can not be activated because it requires at least PHP version %1$s. ',
|
51 |
+
'search-and-replace'
|
52 |
+
),
|
53 |
+
$required_php_version
|
54 |
+
)
|
55 |
+
. '</p> <a href="' . admin_url( 'plugins.php' ) . '">'
|
56 |
+
. esc_attr__( 'back', 'search-and-replace' ) . '</a>'
|
57 |
+
);
|
58 |
+
|
59 |
+
}
|
60 |
+
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Load the plugin
|
65 |
+
*
|
66 |
+
* @since 3.1.1
|
67 |
+
*
|
68 |
+
* @return bool
|
69 |
+
*/
|
70 |
+
function search_replace_load() {
|
71 |
+
|
72 |
+
global $wpdb;
|
73 |
+
|
74 |
+
// all hooks are just available on backend.
|
75 |
+
if ( ! is_admin() ) {
|
76 |
+
return false;
|
77 |
+
}
|
78 |
+
|
79 |
+
define( 'SEARCH_REPLACE_BASEDIR', plugin_dir_url( __FILE__ ) );
|
80 |
+
|
81 |
+
search_replace_textdomain();
|
82 |
+
|
83 |
+
$user_cap = apply_filters( 'search_replace_access_capability', 'manage_options' );
|
84 |
+
$file = __DIR__ . '/vendor/autoload.php';
|
85 |
+
|
86 |
+
if ( ! current_user_can( $user_cap ) || ! file_exists( $file ) ) {
|
87 |
+
return false;
|
88 |
+
}
|
89 |
+
|
90 |
+
/** @noinspection PhpIncludeInspection */
|
91 |
+
include_once $file;
|
92 |
+
|
93 |
+
$max_execution = new Inpsyde\SearchReplace\Service\MaxExecutionTime();
|
94 |
+
|
95 |
+
$dbm = new Database\Manager( $wpdb );
|
96 |
+
$replace = new Database\Replace( $dbm, $max_execution );
|
97 |
+
$dbe = new Database\Exporter( $replace, $dbm, new \WP_Error() );
|
98 |
+
$dbi = new Database\Importer( $max_execution );
|
99 |
+
|
100 |
+
$downloader = new Inpsyde\SearchReplace\FileDownloader( $dbe, $max_execution );
|
101 |
+
add_action( 'init', [ $downloader, 'deliver_backup_file' ] );
|
102 |
+
|
103 |
+
$page_manager = new Page\Manager();
|
104 |
+
$page_manager->add_page( new Page\BackupDatabase( $dbe, $downloader ) );
|
105 |
+
$page_manager->add_page( new Page\SearchReplace( $dbm, $replace, $dbe, $downloader ) );
|
106 |
+
$page_manager->add_page( new Page\ReplaceDomain( $dbm, $dbe, $downloader ) );
|
107 |
+
$page_manager->add_page( new Page\SqlImport( $dbi ) );
|
108 |
+
$page_manager->add_page( new Page\Credits() );
|
109 |
+
|
110 |
+
add_action( 'admin_menu', [ $page_manager, 'register_pages' ] );
|
111 |
+
add_action( 'admin_head', [ $page_manager, 'remove_submenu_pages' ] );
|
112 |
+
|
113 |
+
add_action( 'admin_enqueue_scripts', [ $page_manager, 'register_css' ] );
|
114 |
+
add_action( 'admin_enqueue_scripts', [ $page_manager, 'register_js' ] );
|
115 |
+
|
116 |
+
return true;
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Loading the plugin translations.
|
121 |
+
*/
|
122 |
+
function search_replace_textdomain() {
|
123 |
+
|
124 |
+
return load_plugin_textdomain(
|
125 |
+
'search-and-replace',
|
126 |
+
false,
|
127 |
+
plugin_basename( __DIR__ ) . '/languages/'
|
128 |
+
);
|
129 |
+
}
|
readme.txt
CHANGED
@@ -1,147 +1,154 @@
|
|
1 |
-
=== Search & Replace ===
|
2 |
-
Contributors: inpsyde, Bueltge, derpixler, ChriCo, s-hinse
|
3 |
-
Tags: search, replace, backup, import, sql, migrate, multisite
|
4 |
-
Requires at least: 4.0
|
5 |
-
Tested up to: 5.
|
6 |
-
Requires PHP: 5.6
|
7 |
-
Stable tag: 3.2.
|
8 |
-
License:
|
9 |
-
License URI: https://www.gnu.org/licenses/gpl-
|
10 |
-
|
11 |
-
Search & Replace data in your database with WordPress admin, replace domains/URLs of your WordPress installation.
|
12 |
-
|
13 |
-
== Description ==
|
14 |
-
With Search & Replace you can search for everything and replace this with everything **but before** you do this you can easily **create** a simple **database backup** and restore it.
|
15 |
-
|
16 |
-
For avoiding problem please keep in mind that this plugin search and replace strictly what is specified in "Replace With".
|
17 |
-
Common error example:
|
18 |
-
Search For: http://web.com/wordpress/
|
19 |
-
Replace With: http://neuweb.com/wordpress
|
20 |
-
The url become something like: http://neuweb.com/wordpresscontent/...
|
21 |
-
|
22 |
-
Correct "Replace with":
|
23 |
-
Search For: http://web.com/wordpress/
|
24 |
-
Replace With: http://neuweb.com/wordpress/
|
25 |
-
The url become something like: http://neuweb.com/wordpress/content/...
|
26 |
-
|
27 |
-
**We have
|
28 |
-
|
29 |
-
The
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
-
|
40 |
-
-
|
41 |
-
-
|
42 |
-
-
|
43 |
-
-
|
44 |
-
-
|
45 |
-
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
*
|
69 |
-
*
|
70 |
-
*
|
71 |
-
* Fix
|
72 |
-
|
73 |
-
=
|
74 |
-
*
|
75 |
-
|
76 |
-
|
77 |
-
*
|
78 |
-
*
|
79 |
-
|
80 |
-
= v3.1.
|
81 |
-
*
|
82 |
-
|
83 |
-
|
84 |
-
*
|
85 |
-
*
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
*
|
91 |
-
*
|
92 |
-
*
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
*
|
98 |
-
*
|
99 |
-
*
|
100 |
-
|
101 |
-
|
102 |
-
*
|
103 |
-
*
|
104 |
-
*
|
105 |
-
|
106 |
-
|
107 |
-
*
|
108 |
-
*
|
109 |
-
|
110 |
-
|
111 |
-
*
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
*
|
119 |
-
*
|
120 |
-
*
|
121 |
-
|
122 |
-
= v2.6.
|
123 |
-
*
|
124 |
-
|
125 |
-
|
126 |
-
*
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
* add
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
*
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
*
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
*
|
147 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
=== Search & Replace ===
|
2 |
+
Contributors: inpsyde, Bueltge, derpixler, ChriCo, s-hinse
|
3 |
+
Tags: search, replace, backup, import, sql, migrate, multisite
|
4 |
+
Requires at least: 4.0
|
5 |
+
Tested up to: 5.2
|
6 |
+
Requires PHP: 5.6
|
7 |
+
Stable tag: 3.2.1
|
8 |
+
License: GPLv2 or later
|
9 |
+
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
10 |
+
|
11 |
+
Search & Replace data in your database with WordPress admin, replace domains/URLs of your WordPress installation.
|
12 |
+
|
13 |
+
== Description ==
|
14 |
+
With Search & Replace you can search for everything and replace this with everything **but before** you do this you can easily **create** a simple **database backup** and restore it.
|
15 |
+
|
16 |
+
For avoiding problem please keep in mind that this plugin search and replace strictly what is specified in "Replace With".
|
17 |
+
Common error example:
|
18 |
+
Search For: http://web.com/wordpress/
|
19 |
+
Replace With: http://neuweb.com/wordpress
|
20 |
+
The url become something like: http://neuweb.com/wordpresscontent/...
|
21 |
+
|
22 |
+
Correct "Replace with":
|
23 |
+
Search For: http://web.com/wordpress/
|
24 |
+
Replace With: http://neuweb.com/wordpress/
|
25 |
+
The url become something like: http://neuweb.com/wordpress/content/...
|
26 |
+
|
27 |
+
**We have implemented special features!**
|
28 |
+
|
29 |
+
The first one is "Replace a Domain / URL" that is useful for a quick and simple transfer or a migration of a WordPress site.
|
30 |
+
The second feature is full support for serialized data. There are a lot more features - check them out! :-)
|
31 |
+
|
32 |
+
Our goal with this plugin is to give you a good solution for manipulating your data for both Developers and Users of WordPress.
|
33 |
+
|
34 |
+
> **Note:** This plugin requires PHP 5.6 or higher to be activated.
|
35 |
+
|
36 |
+
[**Checkout our GitHub Repository**](https://github.com/inpsyde/search-and-replace)
|
37 |
+
|
38 |
+
= Features =
|
39 |
+
- Search & replace data in your WordPress database
|
40 |
+
- Change domain/URL of WordPress installation
|
41 |
+
- Handle serialized data
|
42 |
+
- Choose dry run or download SQL file
|
43 |
+
- Change table prefix
|
44 |
+
- Backup & restore your database
|
45 |
+
- WordPress Multisite support
|
46 |
+
- Localized and ready for your own language
|
47 |
+
|
48 |
+
= Crafted by Inpsyde =
|
49 |
+
The team at [Inpsyde](https://inpsyde.com) is engineering the web and WordPress since 2006.
|
50 |
+
|
51 |
+
= Donation? =
|
52 |
+
You want to donate - we prefer a [positive review](https://wordpress.org/support/view/plugin-reviews/search-and-replace?rate=5#postform), not more.
|
53 |
+
|
54 |
+
== Installation ==
|
55 |
+
= Requirements =
|
56 |
+
- WordPress 4.0 (Single and Multisite)
|
57 |
+
- PHP 5.6, newer PHP versions will work faster.
|
58 |
+
|
59 |
+
== Screenshots ==
|
60 |
+
1. Search and Replace
|
61 |
+
2. Replace Domain/URL
|
62 |
+
3. Restore Database
|
63 |
+
4. Backup Database
|
64 |
+
5. Result screen after search or search and replace
|
65 |
+
|
66 |
+
== Changelog ==
|
67 |
+
= 3.2.1 (2019-06-06) =
|
68 |
+
* Update readme for tested up WP versions
|
69 |
+
* Add check for replace function to get more solid replace for custom tables. [#132](https://github.com/inpsyde/search-and-replace/pull/132/files)
|
70 |
+
* Fix small typos
|
71 |
+
* Fix Throwable because we set as minimum php 5.6
|
72 |
+
|
73 |
+
= 3.2.0 (2019-01-17) =
|
74 |
+
* Added CSV format alternative for search/replace [#82](https://github.com/inpsyde/search-and-replace/issues/82).
|
75 |
+
* Improve code structure, preparation for more solid UnitTests.
|
76 |
+
* Improve Modal Table UI.
|
77 |
+
* Added Multiline searching [#119](https://github.com/inpsyde/search-and-replace/issues/119).
|
78 |
+
* Fix several issues to run always with php 5.6 to 7.2.
|
79 |
+
|
80 |
+
= v3.1.2 (2016-12-31) =
|
81 |
+
* hotfix: prevent declaration error with Requisite
|
82 |
+
|
83 |
+
= v3.1.1 (2016-12-24) =
|
84 |
+
* Refactor Plugin loading [#67](https://github.com/inpsyde/search-and-replace/issues/67)
|
85 |
+
* Display error notice is the search value the current domain and save changes to Database selected
|
86 |
+
|
87 |
+
= v3.1.0 (2016-02-07) =
|
88 |
+
* Improve codquality
|
89 |
+
* Prepared for localization (GlotPress)
|
90 |
+
* Prevent doing idle prozesses if search & replace pattern the same
|
91 |
+
* Implement better BigData handling.
|
92 |
+
* Implement better tab and adminpage handling [#33](https://github.com/inpsyde/search-and-replace/issues/33)
|
93 |
+
* Prepare the Plugin for localization, change Text-Domain.[#47](https://github.com/inpsyde/search-and-replace/issues/47)
|
94 |
+
* Remove difference in wordings for buttons between descriptions.[#46](https://github.com/inpsyde/search-and-replace/issues/46)
|
95 |
+
|
96 |
+
= v3.0.1 (2016-02-09) =
|
97 |
+
* Add support for Searchpattern with quotes. [#40](https://github.com/inpsyde/search-and-replace/issues/40)
|
98 |
+
* Basic travis support for travis was added. [#38](https://github.com/inpsyde/search-and-replace/issues/38)
|
99 |
+
* Fix Unittest [#37](https://github.com/inpsyde/search-and-replace/issues/37)
|
100 |
+
|
101 |
+
= v3.0.0 (2016-01-29) =
|
102 |
+
* Refactor the plugin, new requirements, goal and result.
|
103 |
+
* *Thanks to [Sven Hinse](https://github.com/s-hinse/) for help to maintain the plugin*
|
104 |
+
* Changeable table prefix on replace site URL tab enhancement
|
105 |
+
* Implement database backup & import tab
|
106 |
+
* Implement dry Run: Keep for search and replace
|
107 |
+
* Prevent self destroy
|
108 |
+
* Multisite basic support - show only tables of current site
|
109 |
+
* Add special tab for replace the URL
|
110 |
+
* Supports serialized data
|
111 |
+
* Refactor the whole codebase
|
112 |
+
|
113 |
+
= v2.7.1 (2015-05-28) =
|
114 |
+
* Fix for changes on database collate since WordPress version 4.2
|
115 |
+
* Fix to reduce backslashes in search and replace string
|
116 |
+
|
117 |
+
= v2.7.0 (2014-09-14) =
|
118 |
+
* Exclude serialized data from replace function (maybe we reduce the support)
|
119 |
+
* Add hint, if is serialized data on the result table
|
120 |
+
* Fix to see also the result case sensitive
|
121 |
+
|
122 |
+
= v2.6.6 (09/05/2014) =
|
123 |
+
* *Thanks to [Ron Guerin](http://wordpress.org/support/profile/rong) for help to maintain the plugin*
|
124 |
+
* Fix to use $wpdb object for all database access
|
125 |
+
* Fix inability to search and replace quoted strings
|
126 |
+
* Output changes to clarify when searching vs. searching and replacing
|
127 |
+
* Some changes to English strings and string identifiers
|
128 |
+
|
129 |
+
= v2.6.5 =
|
130 |
+
* Fix for change User-ID, add table `comments`
|
131 |
+
|
132 |
+
= v2.6.4 =
|
133 |
+
* Fix capability check, if the constant `DISALLOW_FILE_EDIT` is defined
|
134 |
+
|
135 |
+
= v2.6.3 (10/10/2011) =
|
136 |
+
* filter for return values, html-filter
|
137 |
+
* add belarussian language
|
138 |
+
* add romanian language files
|
139 |
+
|
140 |
+
= v2.6.2 (09/11/2011) =
|
141 |
+
* change right object for use the plugin also on WP smaller 3.0, include 2.9
|
142 |
+
* add function search and replace in all tables of the database - special care!
|
143 |
+
|
144 |
+
= v2.6.1 (01/25/2011) =
|
145 |
+
* Feature: Add Signups-Table for WP MU
|
146 |
+
* Maintenance: check for tables, PHP Warning fix
|
147 |
+
|
148 |
+
= v2.6.0 (01/03/2011) =
|
149 |
+
* Feature: add an new search for find strings (maybe a new way for search strings)
|
150 |
+
* Maintenance: small changes on source
|
151 |
+
|
152 |
+
= v2.5.1 (07/07/2010) =
|
153 |
+
* small changes for use in WP 3.0
|
154 |
+
Status API Training Shop Blog About Pricing
|
vendor/autoload.php
CHANGED
@@ -4,4 +4,4 @@
|
|
4 |
|
5 |
require_once __DIR__ . '/composer/autoload_real.php';
|
6 |
|
7 |
-
return
|
4 |
|
5 |
require_once __DIR__ . '/composer/autoload_real.php';
|
6 |
|
7 |
+
return ComposerAutoloaderInitadd47636e837c2545ad6840e16d99810::getLoader();
|
vendor/composer/ClassLoader.php
CHANGED
@@ -279,7 +279,7 @@ class ClassLoader
|
|
279 |
*/
|
280 |
public function setApcuPrefix($apcuPrefix)
|
281 |
{
|
282 |
-
$this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null;
|
283 |
}
|
284 |
|
285 |
/**
|
279 |
*/
|
280 |
public function setApcuPrefix($apcuPrefix)
|
281 |
{
|
282 |
+
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
|
283 |
}
|
284 |
|
285 |
/**
|
vendor/composer/autoload_real.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
// autoload_real.php @generated by Composer
|
4 |
|
5 |
-
class
|
6 |
{
|
7 |
private static $loader;
|
8 |
|
@@ -19,15 +19,15 @@ class ComposerAutoloaderInit89cbb49124c536405f852edfc948afee
|
|
19 |
return self::$loader;
|
20 |
}
|
21 |
|
22 |
-
spl_autoload_register(array('
|
23 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
24 |
-
spl_autoload_unregister(array('
|
25 |
|
26 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
27 |
if ($useStaticLoader) {
|
28 |
require_once __DIR__ . '/autoload_static.php';
|
29 |
|
30 |
-
call_user_func(\Composer\Autoload\
|
31 |
} else {
|
32 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
33 |
foreach ($map as $namespace => $path) {
|
2 |
|
3 |
// autoload_real.php @generated by Composer
|
4 |
|
5 |
+
class ComposerAutoloaderInitadd47636e837c2545ad6840e16d99810
|
6 |
{
|
7 |
private static $loader;
|
8 |
|
19 |
return self::$loader;
|
20 |
}
|
21 |
|
22 |
+
spl_autoload_register(array('ComposerAutoloaderInitadd47636e837c2545ad6840e16d99810', 'loadClassLoader'), true, true);
|
23 |
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
|
24 |
+
spl_autoload_unregister(array('ComposerAutoloaderInitadd47636e837c2545ad6840e16d99810', 'loadClassLoader'));
|
25 |
|
26 |
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
|
27 |
if ($useStaticLoader) {
|
28 |
require_once __DIR__ . '/autoload_static.php';
|
29 |
|
30 |
+
call_user_func(\Composer\Autoload\ComposerStaticInitadd47636e837c2545ad6840e16d99810::getInitializer($loader));
|
31 |
} else {
|
32 |
$map = require __DIR__ . '/autoload_namespaces.php';
|
33 |
foreach ($map as $namespace => $path) {
|
vendor/composer/autoload_static.php
CHANGED
@@ -4,7 +4,7 @@
|
|
4 |
|
5 |
namespace Composer\Autoload;
|
6 |
|
7 |
-
class
|
8 |
{
|
9 |
public static $prefixLengthsPsr4 = array (
|
10 |
'I' =>
|
@@ -40,9 +40,9 @@ class ComposerStaticInit89cbb49124c536405f852edfc948afee
|
|
40 |
public static function getInitializer(ClassLoader $loader)
|
41 |
{
|
42 |
return \Closure::bind(function () use ($loader) {
|
43 |
-
$loader->prefixLengthsPsr4 =
|
44 |
-
$loader->prefixDirsPsr4 =
|
45 |
-
$loader->classMap =
|
46 |
|
47 |
}, null, ClassLoader::class);
|
48 |
}
|
4 |
|
5 |
namespace Composer\Autoload;
|
6 |
|
7 |
+
class ComposerStaticInitadd47636e837c2545ad6840e16d99810
|
8 |
{
|
9 |
public static $prefixLengthsPsr4 = array (
|
10 |
'I' =>
|
40 |
public static function getInitializer(ClassLoader $loader)
|
41 |
{
|
42 |
return \Closure::bind(function () use ($loader) {
|
43 |
+
$loader->prefixLengthsPsr4 = ComposerStaticInitadd47636e837c2545ad6840e16d99810::$prefixLengthsPsr4;
|
44 |
+
$loader->prefixDirsPsr4 = ComposerStaticInitadd47636e837c2545ad6840e16d99810::$prefixDirsPsr4;
|
45 |
+
$loader->classMap = ComposerStaticInitadd47636e837c2545ad6840e16d99810::$classMap;
|
46 |
|
47 |
}, null, ClassLoader::class);
|
48 |
}
|
vendor/composer/installed.json
CHANGED
@@ -44,17 +44,17 @@
|
|
44 |
},
|
45 |
{
|
46 |
"name": "brain/monkey",
|
47 |
-
"version": "2.2.
|
48 |
-
"version_normalized": "2.2.
|
49 |
"source": {
|
50 |
"type": "git",
|
51 |
"url": "https://github.com/Brain-WP/BrainMonkey.git",
|
52 |
-
"reference": "
|
53 |
},
|
54 |
"dist": {
|
55 |
"type": "zip",
|
56 |
-
"url": "https://api.github.com/repos/Brain-WP/BrainMonkey/zipball/
|
57 |
-
"reference": "
|
58 |
"shasum": ""
|
59 |
},
|
60 |
"require": {
|
@@ -65,7 +65,7 @@
|
|
65 |
"require-dev": {
|
66 |
"phpunit/phpunit": "~5.7.9"
|
67 |
},
|
68 |
-
"time": "
|
69 |
"type": "library",
|
70 |
"extra": {
|
71 |
"branch-alias": {
|
@@ -108,129 +108,19 @@
|
|
108 |
"testing"
|
109 |
]
|
110 |
},
|
111 |
-
{
|
112 |
-
"name": "composer/semver",
|
113 |
-
"version": "1.4.2",
|
114 |
-
"version_normalized": "1.4.2.0",
|
115 |
-
"source": {
|
116 |
-
"type": "git",
|
117 |
-
"url": "https://github.com/composer/semver.git",
|
118 |
-
"reference": "c7cb9a2095a074d131b65a8a0cd294479d785573"
|
119 |
-
},
|
120 |
-
"dist": {
|
121 |
-
"type": "zip",
|
122 |
-
"url": "https://api.github.com/repos/composer/semver/zipball/c7cb9a2095a074d131b65a8a0cd294479d785573",
|
123 |
-
"reference": "c7cb9a2095a074d131b65a8a0cd294479d785573",
|
124 |
-
"shasum": ""
|
125 |
-
},
|
126 |
-
"require": {
|
127 |
-
"php": "^5.3.2 || ^7.0"
|
128 |
-
},
|
129 |
-
"require-dev": {
|
130 |
-
"phpunit/phpunit": "^4.5 || ^5.0.5",
|
131 |
-
"phpunit/phpunit-mock-objects": "2.3.0 || ^3.0"
|
132 |
-
},
|
133 |
-
"time": "2016-08-30T16:08:34+00:00",
|
134 |
-
"type": "library",
|
135 |
-
"extra": {
|
136 |
-
"branch-alias": {
|
137 |
-
"dev-master": "1.x-dev"
|
138 |
-
}
|
139 |
-
},
|
140 |
-
"installation-source": "dist",
|
141 |
-
"autoload": {
|
142 |
-
"psr-4": {
|
143 |
-
"Composer\\Semver\\": "src"
|
144 |
-
}
|
145 |
-
},
|
146 |
-
"notification-url": "https://packagist.org/downloads/",
|
147 |
-
"license": [
|
148 |
-
"MIT"
|
149 |
-
],
|
150 |
-
"authors": [
|
151 |
-
{
|
152 |
-
"name": "Nils Adermann",
|
153 |
-
"email": "naderman@naderman.de",
|
154 |
-
"homepage": "http://www.naderman.de"
|
155 |
-
},
|
156 |
-
{
|
157 |
-
"name": "Jordi Boggiano",
|
158 |
-
"email": "j.boggiano@seld.be",
|
159 |
-
"homepage": "http://seld.be"
|
160 |
-
},
|
161 |
-
{
|
162 |
-
"name": "Rob Bast",
|
163 |
-
"email": "rob.bast@gmail.com",
|
164 |
-
"homepage": "http://robbast.nl"
|
165 |
-
}
|
166 |
-
],
|
167 |
-
"description": "Semver library that offers utilities, version constraint parsing and validation.",
|
168 |
-
"keywords": [
|
169 |
-
"semantic",
|
170 |
-
"semver",
|
171 |
-
"validation",
|
172 |
-
"versioning"
|
173 |
-
]
|
174 |
-
},
|
175 |
-
{
|
176 |
-
"name": "composer/xdebug-handler",
|
177 |
-
"version": "1.3.1",
|
178 |
-
"version_normalized": "1.3.1.0",
|
179 |
-
"source": {
|
180 |
-
"type": "git",
|
181 |
-
"url": "https://github.com/composer/xdebug-handler.git",
|
182 |
-
"reference": "dc523135366eb68f22268d069ea7749486458562"
|
183 |
-
},
|
184 |
-
"dist": {
|
185 |
-
"type": "zip",
|
186 |
-
"url": "https://api.github.com/repos/composer/xdebug-handler/zipball/dc523135366eb68f22268d069ea7749486458562",
|
187 |
-
"reference": "dc523135366eb68f22268d069ea7749486458562",
|
188 |
-
"shasum": ""
|
189 |
-
},
|
190 |
-
"require": {
|
191 |
-
"php": "^5.3.2 || ^7.0",
|
192 |
-
"psr/log": "^1.0"
|
193 |
-
},
|
194 |
-
"require-dev": {
|
195 |
-
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.5"
|
196 |
-
},
|
197 |
-
"time": "2018-11-29T10:59:02+00:00",
|
198 |
-
"type": "library",
|
199 |
-
"installation-source": "dist",
|
200 |
-
"autoload": {
|
201 |
-
"psr-4": {
|
202 |
-
"Composer\\XdebugHandler\\": "src"
|
203 |
-
}
|
204 |
-
},
|
205 |
-
"notification-url": "https://packagist.org/downloads/",
|
206 |
-
"license": [
|
207 |
-
"MIT"
|
208 |
-
],
|
209 |
-
"authors": [
|
210 |
-
{
|
211 |
-
"name": "John Stevenson",
|
212 |
-
"email": "john-stevenson@blueyonder.co.uk"
|
213 |
-
}
|
214 |
-
],
|
215 |
-
"description": "Restarts a process without xdebug.",
|
216 |
-
"keywords": [
|
217 |
-
"Xdebug",
|
218 |
-
"performance"
|
219 |
-
]
|
220 |
-
},
|
221 |
{
|
222 |
"name": "dg/composer-cleaner",
|
223 |
-
"version": "v2.
|
224 |
-
"version_normalized": "2.
|
225 |
"source": {
|
226 |
"type": "git",
|
227 |
"url": "https://github.com/dg/composer-cleaner.git",
|
228 |
-
"reference": "
|
229 |
},
|
230 |
"dist": {
|
231 |
"type": "zip",
|
232 |
-
"url": "https://api.github.com/repos/dg/composer-cleaner/zipball/
|
233 |
-
"reference": "
|
234 |
"shasum": ""
|
235 |
},
|
236 |
"require": {
|
@@ -240,7 +130,7 @@
|
|
240 |
"require-dev": {
|
241 |
"nette/tester": "^1.7"
|
242 |
},
|
243 |
-
"time": "
|
244 |
"type": "composer-plugin",
|
245 |
"extra": {
|
246 |
"class": "DG\\ComposerCleaner\\Plugin"
|
@@ -268,30 +158,32 @@
|
|
268 |
},
|
269 |
{
|
270 |
"name": "doctrine/instantiator",
|
271 |
-
"version": "1.
|
272 |
-
"version_normalized": "1.
|
273 |
"source": {
|
274 |
"type": "git",
|
275 |
"url": "https://github.com/doctrine/instantiator.git",
|
276 |
-
"reference": "
|
277 |
},
|
278 |
"dist": {
|
279 |
"type": "zip",
|
280 |
-
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/
|
281 |
-
"reference": "
|
282 |
"shasum": ""
|
283 |
},
|
284 |
"require": {
|
285 |
"php": "^7.1"
|
286 |
},
|
287 |
"require-dev": {
|
288 |
-
"
|
289 |
"ext-pdo": "*",
|
290 |
"ext-phar": "*",
|
291 |
-
"
|
292 |
-
"
|
|
|
|
|
293 |
},
|
294 |
-
"time": "
|
295 |
"type": "library",
|
296 |
"extra": {
|
297 |
"branch-alias": {
|
@@ -316,55 +208,12 @@
|
|
316 |
}
|
317 |
],
|
318 |
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
|
319 |
-
"homepage": "https://
|
320 |
"keywords": [
|
321 |
"constructor",
|
322 |
"instantiate"
|
323 |
]
|
324 |
},
|
325 |
-
{
|
326 |
-
"name": "felixfbecker/advanced-json-rpc",
|
327 |
-
"version": "v3.0.3",
|
328 |
-
"version_normalized": "3.0.3.0",
|
329 |
-
"source": {
|
330 |
-
"type": "git",
|
331 |
-
"url": "https://github.com/felixfbecker/php-advanced-json-rpc.git",
|
332 |
-
"reference": "241c470695366e7b83672be04ea0e64d8085a551"
|
333 |
-
},
|
334 |
-
"dist": {
|
335 |
-
"type": "zip",
|
336 |
-
"url": "https://api.github.com/repos/felixfbecker/php-advanced-json-rpc/zipball/241c470695366e7b83672be04ea0e64d8085a551",
|
337 |
-
"reference": "241c470695366e7b83672be04ea0e64d8085a551",
|
338 |
-
"shasum": ""
|
339 |
-
},
|
340 |
-
"require": {
|
341 |
-
"netresearch/jsonmapper": "^1.0",
|
342 |
-
"php": ">=7.0",
|
343 |
-
"phpdocumentor/reflection-docblock": "^4.0.0"
|
344 |
-
},
|
345 |
-
"require-dev": {
|
346 |
-
"phpunit/phpunit": "^6.0.0"
|
347 |
-
},
|
348 |
-
"time": "2018-09-10T08:58:41+00:00",
|
349 |
-
"type": "library",
|
350 |
-
"installation-source": "dist",
|
351 |
-
"autoload": {
|
352 |
-
"psr-4": {
|
353 |
-
"AdvancedJsonRpc\\": "lib/"
|
354 |
-
}
|
355 |
-
},
|
356 |
-
"notification-url": "https://packagist.org/downloads/",
|
357 |
-
"license": [
|
358 |
-
"ISC"
|
359 |
-
],
|
360 |
-
"authors": [
|
361 |
-
{
|
362 |
-
"name": "Felix Becker",
|
363 |
-
"email": "felix.b@outlook.com"
|
364 |
-
}
|
365 |
-
],
|
366 |
-
"description": "A more advanced JSONRPC implementation"
|
367 |
-
},
|
368 |
{
|
369 |
"name": "hamcrest/hamcrest-php",
|
370 |
"version": "v2.0.0",
|
@@ -415,62 +264,19 @@
|
|
415 |
"test"
|
416 |
]
|
417 |
},
|
418 |
-
{
|
419 |
-
"name": "microsoft/tolerant-php-parser",
|
420 |
-
"version": "v0.0.15",
|
421 |
-
"version_normalized": "0.0.15.0",
|
422 |
-
"source": {
|
423 |
-
"type": "git",
|
424 |
-
"url": "https://github.com/Microsoft/tolerant-php-parser.git",
|
425 |
-
"reference": "54a84f1250dcde5641e86b5e966fec5f0e201f71"
|
426 |
-
},
|
427 |
-
"dist": {
|
428 |
-
"type": "zip",
|
429 |
-
"url": "https://api.github.com/repos/Microsoft/tolerant-php-parser/zipball/54a84f1250dcde5641e86b5e966fec5f0e201f71",
|
430 |
-
"reference": "54a84f1250dcde5641e86b5e966fec5f0e201f71",
|
431 |
-
"shasum": ""
|
432 |
-
},
|
433 |
-
"require": {
|
434 |
-
"php": ">=7.0"
|
435 |
-
},
|
436 |
-
"require-dev": {
|
437 |
-
"phpunit/phpunit": "^6.4"
|
438 |
-
},
|
439 |
-
"time": "2018-09-26T05:43:26+00:00",
|
440 |
-
"type": "library",
|
441 |
-
"installation-source": "dist",
|
442 |
-
"autoload": {
|
443 |
-
"psr-4": {
|
444 |
-
"Microsoft\\PhpParser\\": [
|
445 |
-
"src/"
|
446 |
-
]
|
447 |
-
}
|
448 |
-
},
|
449 |
-
"notification-url": "https://packagist.org/downloads/",
|
450 |
-
"license": [
|
451 |
-
"MIT"
|
452 |
-
],
|
453 |
-
"authors": [
|
454 |
-
{
|
455 |
-
"name": "Rob Lourens",
|
456 |
-
"email": "roblou@microsoft.com"
|
457 |
-
}
|
458 |
-
],
|
459 |
-
"description": "Tolerant PHP-to-AST parser designed for IDE usage scenarios"
|
460 |
-
},
|
461 |
{
|
462 |
"name": "mockery/mockery",
|
463 |
-
"version": "1.2.
|
464 |
-
"version_normalized": "1.2.
|
465 |
"source": {
|
466 |
"type": "git",
|
467 |
"url": "https://github.com/mockery/mockery.git",
|
468 |
-
"reference": "
|
469 |
},
|
470 |
"dist": {
|
471 |
"type": "zip",
|
472 |
-
"url": "https://api.github.com/repos/mockery/mockery/zipball/
|
473 |
-
"reference": "
|
474 |
"shasum": ""
|
475 |
},
|
476 |
"require": {
|
@@ -479,9 +285,9 @@
|
|
479 |
"php": ">=5.6.0"
|
480 |
},
|
481 |
"require-dev": {
|
482 |
-
"phpunit/phpunit": "~5.7.10|~6.5|~7.0"
|
483 |
},
|
484 |
-
"time": "
|
485 |
"type": "library",
|
486 |
"extra": {
|
487 |
"branch-alias": {
|
@@ -527,17 +333,17 @@
|
|
527 |
},
|
528 |
{
|
529 |
"name": "myclabs/deep-copy",
|
530 |
-
"version": "1.
|
531 |
-
"version_normalized": "1.
|
532 |
"source": {
|
533 |
"type": "git",
|
534 |
"url": "https://github.com/myclabs/DeepCopy.git",
|
535 |
-
"reference": "
|
536 |
},
|
537 |
"dist": {
|
538 |
"type": "zip",
|
539 |
-
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/
|
540 |
-
"reference": "
|
541 |
"shasum": ""
|
542 |
},
|
543 |
"require": {
|
@@ -551,7 +357,7 @@
|
|
551 |
"doctrine/common": "^2.6",
|
552 |
"phpunit/phpunit": "^7.1"
|
553 |
},
|
554 |
-
"time": "
|
555 |
"type": "library",
|
556 |
"installation-source": "dist",
|
557 |
"autoload": {
|
@@ -575,118 +381,6 @@
|
|
575 |
"object graph"
|
576 |
]
|
577 |
},
|
578 |
-
{
|
579 |
-
"name": "netresearch/jsonmapper",
|
580 |
-
"version": "v1.4.0",
|
581 |
-
"version_normalized": "1.4.0.0",
|
582 |
-
"source": {
|
583 |
-
"type": "git",
|
584 |
-
"url": "https://github.com/cweiske/jsonmapper.git",
|
585 |
-
"reference": "3868fe1128ce1169228acdb623359dca74db5ef3"
|
586 |
-
},
|
587 |
-
"dist": {
|
588 |
-
"type": "zip",
|
589 |
-
"url": "https://api.github.com/repos/cweiske/jsonmapper/zipball/3868fe1128ce1169228acdb623359dca74db5ef3",
|
590 |
-
"reference": "3868fe1128ce1169228acdb623359dca74db5ef3",
|
591 |
-
"shasum": ""
|
592 |
-
},
|
593 |
-
"require": {
|
594 |
-
"php": ">=5.6"
|
595 |
-
},
|
596 |
-
"require-dev": {
|
597 |
-
"phpunit/phpunit": "~4.8.35 || ~5.7 || ~6.4",
|
598 |
-
"squizlabs/php_codesniffer": "~1.5"
|
599 |
-
},
|
600 |
-
"time": "2017-11-28T21:30:01+00:00",
|
601 |
-
"type": "library",
|
602 |
-
"installation-source": "dist",
|
603 |
-
"autoload": {
|
604 |
-
"psr-0": {
|
605 |
-
"JsonMapper": "src/"
|
606 |
-
}
|
607 |
-
},
|
608 |
-
"notification-url": "https://packagist.org/downloads/",
|
609 |
-
"license": [
|
610 |
-
"OSL-3.0"
|
611 |
-
],
|
612 |
-
"authors": [
|
613 |
-
{
|
614 |
-
"name": "Christian Weiske",
|
615 |
-
"email": "cweiske@cweiske.de",
|
616 |
-
"homepage": "http://github.com/cweiske/jsonmapper/",
|
617 |
-
"role": "Developer"
|
618 |
-
}
|
619 |
-
],
|
620 |
-
"description": "Map nested JSON structures onto PHP classes"
|
621 |
-
},
|
622 |
-
{
|
623 |
-
"name": "phan/phan",
|
624 |
-
"version": "1.2.0",
|
625 |
-
"version_normalized": "1.2.0.0",
|
626 |
-
"source": {
|
627 |
-
"type": "git",
|
628 |
-
"url": "https://github.com/phan/phan.git",
|
629 |
-
"reference": "e961f8e1458055488795adf3701535562baa526e"
|
630 |
-
},
|
631 |
-
"dist": {
|
632 |
-
"type": "zip",
|
633 |
-
"url": "https://api.github.com/repos/phan/phan/zipball/e961f8e1458055488795adf3701535562baa526e",
|
634 |
-
"reference": "e961f8e1458055488795adf3701535562baa526e",
|
635 |
-
"shasum": ""
|
636 |
-
},
|
637 |
-
"require": {
|
638 |
-
"composer/semver": "^1.4",
|
639 |
-
"composer/xdebug-handler": "^1.3",
|
640 |
-
"ext-filter": "*",
|
641 |
-
"ext-json": "*",
|
642 |
-
"felixfbecker/advanced-json-rpc": "^3.0.3",
|
643 |
-
"microsoft/tolerant-php-parser": "0.0.15",
|
644 |
-
"php": "^7.0.0",
|
645 |
-
"sabre/event": "^5.0",
|
646 |
-
"symfony/console": "^2.3|^3.0|~4.0"
|
647 |
-
},
|
648 |
-
"require-dev": {
|
649 |
-
"phpunit/phpunit": "^6.3.0"
|
650 |
-
},
|
651 |
-
"suggest": {
|
652 |
-
"ext-ast": "Needed for parsing ASTs (unless --use-fallback-parser is used). php-ast ^0.1.5|^1.0.0 is needed.",
|
653 |
-
"ext-tokenizer": "Needed for non-AST support and file/line-based suppressions."
|
654 |
-
},
|
655 |
-
"time": "2019-01-05T15:41:52+00:00",
|
656 |
-
"bin": [
|
657 |
-
"phan",
|
658 |
-
"phan_client",
|
659 |
-
"tocheckstyle"
|
660 |
-
],
|
661 |
-
"type": "project",
|
662 |
-
"installation-source": "dist",
|
663 |
-
"autoload": {
|
664 |
-
"psr-4": {
|
665 |
-
"Phan\\": "src/Phan"
|
666 |
-
}
|
667 |
-
},
|
668 |
-
"notification-url": "https://packagist.org/downloads/",
|
669 |
-
"license": [
|
670 |
-
"MIT"
|
671 |
-
],
|
672 |
-
"authors": [
|
673 |
-
{
|
674 |
-
"name": "Rasmus Lerdorf"
|
675 |
-
},
|
676 |
-
{
|
677 |
-
"name": "Andrew S. Morrison"
|
678 |
-
},
|
679 |
-
{
|
680 |
-
"name": "Tyson Andre"
|
681 |
-
}
|
682 |
-
],
|
683 |
-
"description": "A static analyzer for PHP",
|
684 |
-
"keywords": [
|
685 |
-
"analyzer",
|
686 |
-
"php",
|
687 |
-
"static"
|
688 |
-
]
|
689 |
-
},
|
690 |
{
|
691 |
"name": "phpcompatibility/php-compatibility",
|
692 |
"version": "9.1.1",
|
@@ -909,17 +603,17 @@
|
|
909 |
},
|
910 |
{
|
911 |
"name": "phpdocumentor/reflection-docblock",
|
912 |
-
"version": "4.3.
|
913 |
-
"version_normalized": "4.3.
|
914 |
"source": {
|
915 |
"type": "git",
|
916 |
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
|
917 |
-
"reference": "
|
918 |
},
|
919 |
"dist": {
|
920 |
"type": "zip",
|
921 |
-
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/
|
922 |
-
"reference": "
|
923 |
"shasum": ""
|
924 |
},
|
925 |
"require": {
|
@@ -933,7 +627,7 @@
|
|
933 |
"mockery/mockery": "^1.0",
|
934 |
"phpunit/phpunit": "^6.4"
|
935 |
},
|
936 |
-
"time": "
|
937 |
"type": "library",
|
938 |
"extra": {
|
939 |
"branch-alias": {
|
@@ -1476,118 +1170,8 @@
|
|
1476 |
"keywords": [
|
1477 |
"mock",
|
1478 |
"xunit"
|
1479 |
-
]
|
1480 |
-
},
|
1481 |
-
{
|
1482 |
-
"name": "psr/log",
|
1483 |
-
"version": "1.1.0",
|
1484 |
-
"version_normalized": "1.1.0.0",
|
1485 |
-
"source": {
|
1486 |
-
"type": "git",
|
1487 |
-
"url": "https://github.com/php-fig/log.git",
|
1488 |
-
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd"
|
1489 |
-
},
|
1490 |
-
"dist": {
|
1491 |
-
"type": "zip",
|
1492 |
-
"url": "https://api.github.com/repos/php-fig/log/zipball/6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
|
1493 |
-
"reference": "6c001f1daafa3a3ac1d8ff69ee4db8e799a654dd",
|
1494 |
-
"shasum": ""
|
1495 |
-
},
|
1496 |
-
"require": {
|
1497 |
-
"php": ">=5.3.0"
|
1498 |
-
},
|
1499 |
-
"time": "2018-11-20T15:27:04+00:00",
|
1500 |
-
"type": "library",
|
1501 |
-
"extra": {
|
1502 |
-
"branch-alias": {
|
1503 |
-
"dev-master": "1.0.x-dev"
|
1504 |
-
}
|
1505 |
-
},
|
1506 |
-
"installation-source": "dist",
|
1507 |
-
"autoload": {
|
1508 |
-
"psr-4": {
|
1509 |
-
"Psr\\Log\\": "Psr/Log/"
|
1510 |
-
}
|
1511 |
-
},
|
1512 |
-
"notification-url": "https://packagist.org/downloads/",
|
1513 |
-
"license": [
|
1514 |
-
"MIT"
|
1515 |
-
],
|
1516 |
-
"authors": [
|
1517 |
-
{
|
1518 |
-
"name": "PHP-FIG",
|
1519 |
-
"homepage": "http://www.php-fig.org/"
|
1520 |
-
}
|
1521 |
-
],
|
1522 |
-
"description": "Common interface for logging libraries",
|
1523 |
-
"homepage": "https://github.com/php-fig/log",
|
1524 |
-
"keywords": [
|
1525 |
-
"log",
|
1526 |
-
"psr",
|
1527 |
-
"psr-3"
|
1528 |
-
]
|
1529 |
-
},
|
1530 |
-
{
|
1531 |
-
"name": "sabre/event",
|
1532 |
-
"version": "5.0.3",
|
1533 |
-
"version_normalized": "5.0.3.0",
|
1534 |
-
"source": {
|
1535 |
-
"type": "git",
|
1536 |
-
"url": "https://github.com/sabre-io/event.git",
|
1537 |
-
"reference": "f5cf802d240df1257866d8813282b98aee3bc548"
|
1538 |
-
},
|
1539 |
-
"dist": {
|
1540 |
-
"type": "zip",
|
1541 |
-
"url": "https://api.github.com/repos/sabre-io/event/zipball/f5cf802d240df1257866d8813282b98aee3bc548",
|
1542 |
-
"reference": "f5cf802d240df1257866d8813282b98aee3bc548",
|
1543 |
-
"shasum": ""
|
1544 |
-
},
|
1545 |
-
"require": {
|
1546 |
-
"php": ">=7.0"
|
1547 |
-
},
|
1548 |
-
"require-dev": {
|
1549 |
-
"phpunit/phpunit": ">=6",
|
1550 |
-
"sabre/cs": "~1.0.0"
|
1551 |
-
},
|
1552 |
-
"time": "2018-03-05T13:55:47+00:00",
|
1553 |
-
"type": "library",
|
1554 |
-
"installation-source": "dist",
|
1555 |
-
"autoload": {
|
1556 |
-
"psr-4": {
|
1557 |
-
"Sabre\\Event\\": "lib/"
|
1558 |
-
},
|
1559 |
-
"files": [
|
1560 |
-
"lib/coroutine.php",
|
1561 |
-
"lib/Loop/functions.php",
|
1562 |
-
"lib/Promise/functions.php"
|
1563 |
-
]
|
1564 |
-
},
|
1565 |
-
"notification-url": "https://packagist.org/downloads/",
|
1566 |
-
"license": [
|
1567 |
-
"BSD-3-Clause"
|
1568 |
],
|
1569 |
-
"
|
1570 |
-
{
|
1571 |
-
"name": "Evert Pot",
|
1572 |
-
"email": "me@evertpot.com",
|
1573 |
-
"homepage": "http://evertpot.com/",
|
1574 |
-
"role": "Developer"
|
1575 |
-
}
|
1576 |
-
],
|
1577 |
-
"description": "sabre/event is a library for lightweight event-based programming",
|
1578 |
-
"homepage": "http://sabre.io/event/",
|
1579 |
-
"keywords": [
|
1580 |
-
"EventEmitter",
|
1581 |
-
"async",
|
1582 |
-
"coroutine",
|
1583 |
-
"eventloop",
|
1584 |
-
"events",
|
1585 |
-
"hooks",
|
1586 |
-
"plugin",
|
1587 |
-
"promise",
|
1588 |
-
"reactor",
|
1589 |
-
"signal"
|
1590 |
-
]
|
1591 |
},
|
1592 |
{
|
1593 |
"name": "sebastian/code-unit-reverse-lookup",
|
@@ -2124,17 +1708,17 @@
|
|
2124 |
},
|
2125 |
{
|
2126 |
"name": "squizlabs/php_codesniffer",
|
2127 |
-
"version": "3.4.
|
2128 |
-
"version_normalized": "3.4.
|
2129 |
"source": {
|
2130 |
"type": "git",
|
2131 |
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
2132 |
-
"reference": "
|
2133 |
},
|
2134 |
"dist": {
|
2135 |
"type": "zip",
|
2136 |
-
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/
|
2137 |
-
"reference": "
|
2138 |
"shasum": ""
|
2139 |
},
|
2140 |
"require": {
|
@@ -2146,7 +1730,7 @@
|
|
2146 |
"require-dev": {
|
2147 |
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
2148 |
},
|
2149 |
-
"time": "
|
2150 |
"bin": [
|
2151 |
"bin/phpcs",
|
2152 |
"bin/phpcbf"
|
@@ -2169,166 +1753,25 @@
|
|
2169 |
}
|
2170 |
],
|
2171 |
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
2172 |
-
"homepage": "
|
2173 |
"keywords": [
|
2174 |
"phpcs",
|
2175 |
"standards"
|
2176 |
]
|
2177 |
},
|
2178 |
-
{
|
2179 |
-
"name": "symfony/console",
|
2180 |
-
"version": "v4.2.2",
|
2181 |
-
"version_normalized": "4.2.2.0",
|
2182 |
-
"source": {
|
2183 |
-
"type": "git",
|
2184 |
-
"url": "https://github.com/symfony/console.git",
|
2185 |
-
"reference": "b0a03c1bb0fcbe288629956cf2f1dd3f1dc97522"
|
2186 |
-
},
|
2187 |
-
"dist": {
|
2188 |
-
"type": "zip",
|
2189 |
-
"url": "https://api.github.com/repos/symfony/console/zipball/b0a03c1bb0fcbe288629956cf2f1dd3f1dc97522",
|
2190 |
-
"reference": "b0a03c1bb0fcbe288629956cf2f1dd3f1dc97522",
|
2191 |
-
"shasum": ""
|
2192 |
-
},
|
2193 |
-
"require": {
|
2194 |
-
"php": "^7.1.3",
|
2195 |
-
"symfony/contracts": "^1.0",
|
2196 |
-
"symfony/polyfill-mbstring": "~1.0"
|
2197 |
-
},
|
2198 |
-
"conflict": {
|
2199 |
-
"symfony/dependency-injection": "<3.4",
|
2200 |
-
"symfony/process": "<3.3"
|
2201 |
-
},
|
2202 |
-
"require-dev": {
|
2203 |
-
"psr/log": "~1.0",
|
2204 |
-
"symfony/config": "~3.4|~4.0",
|
2205 |
-
"symfony/dependency-injection": "~3.4|~4.0",
|
2206 |
-
"symfony/event-dispatcher": "~3.4|~4.0",
|
2207 |
-
"symfony/lock": "~3.4|~4.0",
|
2208 |
-
"symfony/process": "~3.4|~4.0"
|
2209 |
-
},
|
2210 |
-
"suggest": {
|
2211 |
-
"psr/log-implementation": "For using the console logger",
|
2212 |
-
"symfony/event-dispatcher": "",
|
2213 |
-
"symfony/lock": "",
|
2214 |
-
"symfony/process": ""
|
2215 |
-
},
|
2216 |
-
"time": "2019-01-04T15:13:53+00:00",
|
2217 |
-
"type": "library",
|
2218 |
-
"extra": {
|
2219 |
-
"branch-alias": {
|
2220 |
-
"dev-master": "4.2-dev"
|
2221 |
-
}
|
2222 |
-
},
|
2223 |
-
"installation-source": "dist",
|
2224 |
-
"autoload": {
|
2225 |
-
"psr-4": {
|
2226 |
-
"Symfony\\Component\\Console\\": ""
|
2227 |
-
},
|
2228 |
-
"exclude-from-classmap": [
|
2229 |
-
"/Tests/"
|
2230 |
-
]
|
2231 |
-
},
|
2232 |
-
"notification-url": "https://packagist.org/downloads/",
|
2233 |
-
"license": [
|
2234 |
-
"MIT"
|
2235 |
-
],
|
2236 |
-
"authors": [
|
2237 |
-
{
|
2238 |
-
"name": "Fabien Potencier",
|
2239 |
-
"email": "fabien@symfony.com"
|
2240 |
-
},
|
2241 |
-
{
|
2242 |
-
"name": "Symfony Community",
|
2243 |
-
"homepage": "https://symfony.com/contributors"
|
2244 |
-
}
|
2245 |
-
],
|
2246 |
-
"description": "Symfony Console Component",
|
2247 |
-
"homepage": "https://symfony.com"
|
2248 |
-
},
|
2249 |
-
{
|
2250 |
-
"name": "symfony/contracts",
|
2251 |
-
"version": "v1.0.2",
|
2252 |
-
"version_normalized": "1.0.2.0",
|
2253 |
-
"source": {
|
2254 |
-
"type": "git",
|
2255 |
-
"url": "https://github.com/symfony/contracts.git",
|
2256 |
-
"reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf"
|
2257 |
-
},
|
2258 |
-
"dist": {
|
2259 |
-
"type": "zip",
|
2260 |
-
"url": "https://api.github.com/repos/symfony/contracts/zipball/1aa7ab2429c3d594dd70689604b5cf7421254cdf",
|
2261 |
-
"reference": "1aa7ab2429c3d594dd70689604b5cf7421254cdf",
|
2262 |
-
"shasum": ""
|
2263 |
-
},
|
2264 |
-
"require": {
|
2265 |
-
"php": "^7.1.3"
|
2266 |
-
},
|
2267 |
-
"require-dev": {
|
2268 |
-
"psr/cache": "^1.0",
|
2269 |
-
"psr/container": "^1.0"
|
2270 |
-
},
|
2271 |
-
"suggest": {
|
2272 |
-
"psr/cache": "When using the Cache contracts",
|
2273 |
-
"psr/container": "When using the Service contracts",
|
2274 |
-
"symfony/cache-contracts-implementation": "",
|
2275 |
-
"symfony/service-contracts-implementation": "",
|
2276 |
-
"symfony/translation-contracts-implementation": ""
|
2277 |
-
},
|
2278 |
-
"time": "2018-12-05T08:06:11+00:00",
|
2279 |
-
"type": "library",
|
2280 |
-
"extra": {
|
2281 |
-
"branch-alias": {
|
2282 |
-
"dev-master": "1.0-dev"
|
2283 |
-
}
|
2284 |
-
},
|
2285 |
-
"installation-source": "dist",
|
2286 |
-
"autoload": {
|
2287 |
-
"psr-4": {
|
2288 |
-
"Symfony\\Contracts\\": ""
|
2289 |
-
},
|
2290 |
-
"exclude-from-classmap": [
|
2291 |
-
"**/Tests/"
|
2292 |
-
]
|
2293 |
-
},
|
2294 |
-
"notification-url": "https://packagist.org/downloads/",
|
2295 |
-
"license": [
|
2296 |
-
"MIT"
|
2297 |
-
],
|
2298 |
-
"authors": [
|
2299 |
-
{
|
2300 |
-
"name": "Nicolas Grekas",
|
2301 |
-
"email": "p@tchwork.com"
|
2302 |
-
},
|
2303 |
-
{
|
2304 |
-
"name": "Symfony Community",
|
2305 |
-
"homepage": "https://symfony.com/contributors"
|
2306 |
-
}
|
2307 |
-
],
|
2308 |
-
"description": "A set of abstractions extracted out of the Symfony components",
|
2309 |
-
"homepage": "https://symfony.com",
|
2310 |
-
"keywords": [
|
2311 |
-
"abstractions",
|
2312 |
-
"contracts",
|
2313 |
-
"decoupling",
|
2314 |
-
"interfaces",
|
2315 |
-
"interoperability",
|
2316 |
-
"standards"
|
2317 |
-
]
|
2318 |
-
},
|
2319 |
{
|
2320 |
"name": "symfony/polyfill-ctype",
|
2321 |
-
"version": "v1.
|
2322 |
-
"version_normalized": "1.
|
2323 |
"source": {
|
2324 |
"type": "git",
|
2325 |
"url": "https://github.com/symfony/polyfill-ctype.git",
|
2326 |
-
"reference": "
|
2327 |
},
|
2328 |
"dist": {
|
2329 |
"type": "zip",
|
2330 |
-
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/
|
2331 |
-
"reference": "
|
2332 |
"shasum": ""
|
2333 |
},
|
2334 |
"require": {
|
@@ -2337,11 +1780,11 @@
|
|
2337 |
"suggest": {
|
2338 |
"ext-ctype": "For best performance"
|
2339 |
},
|
2340 |
-
"time": "
|
2341 |
"type": "library",
|
2342 |
"extra": {
|
2343 |
"branch-alias": {
|
2344 |
-
"dev-master": "1.
|
2345 |
}
|
2346 |
},
|
2347 |
"installation-source": "dist",
|
@@ -2376,80 +1819,19 @@
|
|
2376 |
"portable"
|
2377 |
]
|
2378 |
},
|
2379 |
-
{
|
2380 |
-
"name": "symfony/polyfill-mbstring",
|
2381 |
-
"version": "v1.10.0",
|
2382 |
-
"version_normalized": "1.10.0.0",
|
2383 |
-
"source": {
|
2384 |
-
"type": "git",
|
2385 |
-
"url": "https://github.com/symfony/polyfill-mbstring.git",
|
2386 |
-
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494"
|
2387 |
-
},
|
2388 |
-
"dist": {
|
2389 |
-
"type": "zip",
|
2390 |
-
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/c79c051f5b3a46be09205c73b80b346e4153e494",
|
2391 |
-
"reference": "c79c051f5b3a46be09205c73b80b346e4153e494",
|
2392 |
-
"shasum": ""
|
2393 |
-
},
|
2394 |
-
"require": {
|
2395 |
-
"php": ">=5.3.3"
|
2396 |
-
},
|
2397 |
-
"suggest": {
|
2398 |
-
"ext-mbstring": "For best performance"
|
2399 |
-
},
|
2400 |
-
"time": "2018-09-21T13:07:52+00:00",
|
2401 |
-
"type": "library",
|
2402 |
-
"extra": {
|
2403 |
-
"branch-alias": {
|
2404 |
-
"dev-master": "1.9-dev"
|
2405 |
-
}
|
2406 |
-
},
|
2407 |
-
"installation-source": "dist",
|
2408 |
-
"autoload": {
|
2409 |
-
"psr-4": {
|
2410 |
-
"Symfony\\Polyfill\\Mbstring\\": ""
|
2411 |
-
},
|
2412 |
-
"files": [
|
2413 |
-
"bootstrap.php"
|
2414 |
-
]
|
2415 |
-
},
|
2416 |
-
"notification-url": "https://packagist.org/downloads/",
|
2417 |
-
"license": [
|
2418 |
-
"MIT"
|
2419 |
-
],
|
2420 |
-
"authors": [
|
2421 |
-
{
|
2422 |
-
"name": "Nicolas Grekas",
|
2423 |
-
"email": "p@tchwork.com"
|
2424 |
-
},
|
2425 |
-
{
|
2426 |
-
"name": "Symfony Community",
|
2427 |
-
"homepage": "https://symfony.com/contributors"
|
2428 |
-
}
|
2429 |
-
],
|
2430 |
-
"description": "Symfony polyfill for the Mbstring extension",
|
2431 |
-
"homepage": "https://symfony.com",
|
2432 |
-
"keywords": [
|
2433 |
-
"compatibility",
|
2434 |
-
"mbstring",
|
2435 |
-
"polyfill",
|
2436 |
-
"portable",
|
2437 |
-
"shim"
|
2438 |
-
]
|
2439 |
-
},
|
2440 |
{
|
2441 |
"name": "symfony/yaml",
|
2442 |
-
"version": "v4.
|
2443 |
-
"version_normalized": "4.
|
2444 |
"source": {
|
2445 |
"type": "git",
|
2446 |
"url": "https://github.com/symfony/yaml.git",
|
2447 |
-
"reference": "
|
2448 |
},
|
2449 |
"dist": {
|
2450 |
"type": "zip",
|
2451 |
-
"url": "https://api.github.com/repos/symfony/yaml/zipball/
|
2452 |
-
"reference": "
|
2453 |
"shasum": ""
|
2454 |
},
|
2455 |
"require": {
|
@@ -2465,11 +1847,11 @@
|
|
2465 |
"suggest": {
|
2466 |
"symfony/console": "For validating YAML files using the lint command"
|
2467 |
},
|
2468 |
-
"time": "2019-
|
2469 |
"type": "library",
|
2470 |
"extra": {
|
2471 |
"branch-alias": {
|
2472 |
-
"dev-master": "4.
|
2473 |
}
|
2474 |
},
|
2475 |
"installation-source": "dist",
|
@@ -2553,17 +1935,17 @@
|
|
2553 |
},
|
2554 |
{
|
2555 |
"name": "wp-coding-standards/wpcs",
|
2556 |
-
"version": "2.
|
2557 |
-
"version_normalized": "2.
|
2558 |
"source": {
|
2559 |
"type": "git",
|
2560 |
"url": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git",
|
2561 |
-
"reference": "
|
2562 |
},
|
2563 |
"dist": {
|
2564 |
"type": "zip",
|
2565 |
-
"url": "https://api.github.com/repos/WordPress-Coding-Standards/WordPress-Coding-Standards/zipball/
|
2566 |
-
"reference": "
|
2567 |
"shasum": ""
|
2568 |
},
|
2569 |
"require": {
|
@@ -2576,9 +1958,9 @@
|
|
2576 |
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
2577 |
},
|
2578 |
"suggest": {
|
2579 |
-
"dealerdirect/phpcodesniffer-composer-installer": "^0.
|
2580 |
},
|
2581 |
-
"time": "2019-
|
2582 |
"type": "phpcodesniffer-standard",
|
2583 |
"installation-source": "dist",
|
2584 |
"notification-url": "https://packagist.org/downloads/",
|
44 |
},
|
45 |
{
|
46 |
"name": "brain/monkey",
|
47 |
+
"version": "2.2.1",
|
48 |
+
"version_normalized": "2.2.1.0",
|
49 |
"source": {
|
50 |
"type": "git",
|
51 |
"url": "https://github.com/Brain-WP/BrainMonkey.git",
|
52 |
+
"reference": "326a537bf518edd61bc57ab275e8b075ebb8a1a9"
|
53 |
},
|
54 |
"dist": {
|
55 |
"type": "zip",
|
56 |
+
"url": "https://api.github.com/repos/Brain-WP/BrainMonkey/zipball/326a537bf518edd61bc57ab275e8b075ebb8a1a9",
|
57 |
+
"reference": "326a537bf518edd61bc57ab275e8b075ebb8a1a9",
|
58 |
"shasum": ""
|
59 |
},
|
60 |
"require": {
|
65 |
"require-dev": {
|
66 |
"phpunit/phpunit": "~5.7.9"
|
67 |
},
|
68 |
+
"time": "2019-03-15T13:42:24+00:00",
|
69 |
"type": "library",
|
70 |
"extra": {
|
71 |
"branch-alias": {
|
108 |
"testing"
|
109 |
]
|
110 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
111 |
{
|
112 |
"name": "dg/composer-cleaner",
|
113 |
+
"version": "v2.1",
|
114 |
+
"version_normalized": "2.1.0.0",
|
115 |
"source": {
|
116 |
"type": "git",
|
117 |
"url": "https://github.com/dg/composer-cleaner.git",
|
118 |
+
"reference": "91f865f0b50c66dd647955a0e5ba7745d8086945"
|
119 |
},
|
120 |
"dist": {
|
121 |
"type": "zip",
|
122 |
+
"url": "https://api.github.com/repos/dg/composer-cleaner/zipball/91f865f0b50c66dd647955a0e5ba7745d8086945",
|
123 |
+
"reference": "91f865f0b50c66dd647955a0e5ba7745d8086945",
|
124 |
"shasum": ""
|
125 |
},
|
126 |
"require": {
|
130 |
"require-dev": {
|
131 |
"nette/tester": "^1.7"
|
132 |
},
|
133 |
+
"time": "2019-02-05T21:18:31+00:00",
|
134 |
"type": "composer-plugin",
|
135 |
"extra": {
|
136 |
"class": "DG\\ComposerCleaner\\Plugin"
|
158 |
},
|
159 |
{
|
160 |
"name": "doctrine/instantiator",
|
161 |
+
"version": "1.2.0",
|
162 |
+
"version_normalized": "1.2.0.0",
|
163 |
"source": {
|
164 |
"type": "git",
|
165 |
"url": "https://github.com/doctrine/instantiator.git",
|
166 |
+
"reference": "a2c590166b2133a4633738648b6b064edae0814a"
|
167 |
},
|
168 |
"dist": {
|
169 |
"type": "zip",
|
170 |
+
"url": "https://api.github.com/repos/doctrine/instantiator/zipball/a2c590166b2133a4633738648b6b064edae0814a",
|
171 |
+
"reference": "a2c590166b2133a4633738648b6b064edae0814a",
|
172 |
"shasum": ""
|
173 |
},
|
174 |
"require": {
|
175 |
"php": "^7.1"
|
176 |
},
|
177 |
"require-dev": {
|
178 |
+
"doctrine/coding-standard": "^6.0",
|
179 |
"ext-pdo": "*",
|
180 |
"ext-phar": "*",
|
181 |
+
"phpbench/phpbench": "^0.13",
|
182 |
+
"phpstan/phpstan-phpunit": "^0.11",
|
183 |
+
"phpstan/phpstan-shim": "^0.11",
|
184 |
+
"phpunit/phpunit": "^7.0"
|
185 |
},
|
186 |
+
"time": "2019-03-17T17:37:11+00:00",
|
187 |
"type": "library",
|
188 |
"extra": {
|
189 |
"branch-alias": {
|
208 |
}
|
209 |
],
|
210 |
"description": "A small, lightweight utility to instantiate objects in PHP without invoking their constructors",
|
211 |
+
"homepage": "https://www.doctrine-project.org/projects/instantiator.html",
|
212 |
"keywords": [
|
213 |
"constructor",
|
214 |
"instantiate"
|
215 |
]
|
216 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
217 |
{
|
218 |
"name": "hamcrest/hamcrest-php",
|
219 |
"version": "v2.0.0",
|
264 |
"test"
|
265 |
]
|
266 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
267 |
{
|
268 |
"name": "mockery/mockery",
|
269 |
+
"version": "1.2.2",
|
270 |
+
"version_normalized": "1.2.2.0",
|
271 |
"source": {
|
272 |
"type": "git",
|
273 |
"url": "https://github.com/mockery/mockery.git",
|
274 |
+
"reference": "0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2"
|
275 |
},
|
276 |
"dist": {
|
277 |
"type": "zip",
|
278 |
+
"url": "https://api.github.com/repos/mockery/mockery/zipball/0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2",
|
279 |
+
"reference": "0eb0b48c3f07b3b89f5169ce005b7d05b18cf1d2",
|
280 |
"shasum": ""
|
281 |
},
|
282 |
"require": {
|
285 |
"php": ">=5.6.0"
|
286 |
},
|
287 |
"require-dev": {
|
288 |
+
"phpunit/phpunit": "~5.7.10|~6.5|~7.0|~8.0"
|
289 |
},
|
290 |
+
"time": "2019-02-13T09:37:52+00:00",
|
291 |
"type": "library",
|
292 |
"extra": {
|
293 |
"branch-alias": {
|
333 |
},
|
334 |
{
|
335 |
"name": "myclabs/deep-copy",
|
336 |
+
"version": "1.9.1",
|
337 |
+
"version_normalized": "1.9.1.0",
|
338 |
"source": {
|
339 |
"type": "git",
|
340 |
"url": "https://github.com/myclabs/DeepCopy.git",
|
341 |
+
"reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72"
|
342 |
},
|
343 |
"dist": {
|
344 |
"type": "zip",
|
345 |
+
"url": "https://api.github.com/repos/myclabs/DeepCopy/zipball/e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72",
|
346 |
+
"reference": "e6828efaba2c9b79f4499dae1d66ef8bfa7b2b72",
|
347 |
"shasum": ""
|
348 |
},
|
349 |
"require": {
|
357 |
"doctrine/common": "^2.6",
|
358 |
"phpunit/phpunit": "^7.1"
|
359 |
},
|
360 |
+
"time": "2019-04-07T13:18:21+00:00",
|
361 |
"type": "library",
|
362 |
"installation-source": "dist",
|
363 |
"autoload": {
|
381 |
"object graph"
|
382 |
]
|
383 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
384 |
{
|
385 |
"name": "phpcompatibility/php-compatibility",
|
386 |
"version": "9.1.1",
|
603 |
},
|
604 |
{
|
605 |
"name": "phpdocumentor/reflection-docblock",
|
606 |
+
"version": "4.3.1",
|
607 |
+
"version_normalized": "4.3.1.0",
|
608 |
"source": {
|
609 |
"type": "git",
|
610 |
"url": "https://github.com/phpDocumentor/ReflectionDocBlock.git",
|
611 |
+
"reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c"
|
612 |
},
|
613 |
"dist": {
|
614 |
"type": "zip",
|
615 |
+
"url": "https://api.github.com/repos/phpDocumentor/ReflectionDocBlock/zipball/bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c",
|
616 |
+
"reference": "bdd9f737ebc2a01c06ea7ff4308ec6697db9b53c",
|
617 |
"shasum": ""
|
618 |
},
|
619 |
"require": {
|
627 |
"mockery/mockery": "^1.0",
|
628 |
"phpunit/phpunit": "^6.4"
|
629 |
},
|
630 |
+
"time": "2019-04-30T17:48:53+00:00",
|
631 |
"type": "library",
|
632 |
"extra": {
|
633 |
"branch-alias": {
|
1170 |
"keywords": [
|
1171 |
"mock",
|
1172 |
"xunit"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1173 |
],
|
1174 |
+
"abandoned": true
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1175 |
},
|
1176 |
{
|
1177 |
"name": "sebastian/code-unit-reverse-lookup",
|
1708 |
},
|
1709 |
{
|
1710 |
"name": "squizlabs/php_codesniffer",
|
1711 |
+
"version": "3.4.2",
|
1712 |
+
"version_normalized": "3.4.2.0",
|
1713 |
"source": {
|
1714 |
"type": "git",
|
1715 |
"url": "https://github.com/squizlabs/PHP_CodeSniffer.git",
|
1716 |
+
"reference": "b8a7362af1cc1aadb5bd36c3defc4dda2cf5f0a8"
|
1717 |
},
|
1718 |
"dist": {
|
1719 |
"type": "zip",
|
1720 |
+
"url": "https://api.github.com/repos/squizlabs/PHP_CodeSniffer/zipball/b8a7362af1cc1aadb5bd36c3defc4dda2cf5f0a8",
|
1721 |
+
"reference": "b8a7362af1cc1aadb5bd36c3defc4dda2cf5f0a8",
|
1722 |
"shasum": ""
|
1723 |
},
|
1724 |
"require": {
|
1730 |
"require-dev": {
|
1731 |
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
1732 |
},
|
1733 |
+
"time": "2019-04-10T23:49:02+00:00",
|
1734 |
"bin": [
|
1735 |
"bin/phpcs",
|
1736 |
"bin/phpcbf"
|
1753 |
}
|
1754 |
],
|
1755 |
"description": "PHP_CodeSniffer tokenizes PHP, JavaScript and CSS files and detects violations of a defined set of coding standards.",
|
1756 |
+
"homepage": "https://github.com/squizlabs/PHP_CodeSniffer",
|
1757 |
"keywords": [
|
1758 |
"phpcs",
|
1759 |
"standards"
|
1760 |
]
|
1761 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1762 |
{
|
1763 |
"name": "symfony/polyfill-ctype",
|
1764 |
+
"version": "v1.11.0",
|
1765 |
+
"version_normalized": "1.11.0.0",
|
1766 |
"source": {
|
1767 |
"type": "git",
|
1768 |
"url": "https://github.com/symfony/polyfill-ctype.git",
|
1769 |
+
"reference": "82ebae02209c21113908c229e9883c419720738a"
|
1770 |
},
|
1771 |
"dist": {
|
1772 |
"type": "zip",
|
1773 |
+
"url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/82ebae02209c21113908c229e9883c419720738a",
|
1774 |
+
"reference": "82ebae02209c21113908c229e9883c419720738a",
|
1775 |
"shasum": ""
|
1776 |
},
|
1777 |
"require": {
|
1780 |
"suggest": {
|
1781 |
"ext-ctype": "For best performance"
|
1782 |
},
|
1783 |
+
"time": "2019-02-06T07:57:58+00:00",
|
1784 |
"type": "library",
|
1785 |
"extra": {
|
1786 |
"branch-alias": {
|
1787 |
+
"dev-master": "1.11-dev"
|
1788 |
}
|
1789 |
},
|
1790 |
"installation-source": "dist",
|
1819 |
"portable"
|
1820 |
]
|
1821 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1822 |
{
|
1823 |
"name": "symfony/yaml",
|
1824 |
+
"version": "v4.3.0",
|
1825 |
+
"version_normalized": "4.3.0.0",
|
1826 |
"source": {
|
1827 |
"type": "git",
|
1828 |
"url": "https://github.com/symfony/yaml.git",
|
1829 |
+
"reference": "c60ecf5ba842324433b46f58dc7afc4487dbab99"
|
1830 |
},
|
1831 |
"dist": {
|
1832 |
"type": "zip",
|
1833 |
+
"url": "https://api.github.com/repos/symfony/yaml/zipball/c60ecf5ba842324433b46f58dc7afc4487dbab99",
|
1834 |
+
"reference": "c60ecf5ba842324433b46f58dc7afc4487dbab99",
|
1835 |
"shasum": ""
|
1836 |
},
|
1837 |
"require": {
|
1847 |
"suggest": {
|
1848 |
"symfony/console": "For validating YAML files using the lint command"
|
1849 |
},
|
1850 |
+
"time": "2019-04-06T14:04:46+00:00",
|
1851 |
"type": "library",
|
1852 |
"extra": {
|
1853 |
"branch-alias": {
|
1854 |
+
"dev-master": "4.3-dev"
|
1855 |
}
|
1856 |
},
|
1857 |
"installation-source": "dist",
|
1935 |
},
|
1936 |
{
|
1937 |
"name": "wp-coding-standards/wpcs",
|
1938 |
+
"version": "2.1.1",
|
1939 |
+
"version_normalized": "2.1.1.0",
|
1940 |
"source": {
|
1941 |
"type": "git",
|
1942 |
"url": "https://github.com/WordPress-Coding-Standards/WordPress-Coding-Standards.git",
|
1943 |
+
"reference": "bd9c33152115e6741e3510ff7189605b35167908"
|
1944 |
},
|
1945 |
"dist": {
|
1946 |
"type": "zip",
|
1947 |
+
"url": "https://api.github.com/repos/WordPress-Coding-Standards/WordPress-Coding-Standards/zipball/bd9c33152115e6741e3510ff7189605b35167908",
|
1948 |
+
"reference": "bd9c33152115e6741e3510ff7189605b35167908",
|
1949 |
"shasum": ""
|
1950 |
},
|
1951 |
"require": {
|
1958 |
"phpunit/phpunit": "^4.0 || ^5.0 || ^6.0 || ^7.0"
|
1959 |
},
|
1960 |
"suggest": {
|
1961 |
+
"dealerdirect/phpcodesniffer-composer-installer": "^0.5.0 || This Composer plugin will sort out the PHPCS 'installed_paths' automatically."
|
1962 |
},
|
1963 |
+
"time": "2019-05-21T02:50:00+00:00",
|
1964 |
"type": "phpcodesniffer-standard",
|
1965 |
"installation-source": "dist",
|
1966 |
"notification-url": "https://packagist.org/downloads/",
|