Version Description
Download this release
Release Info
Developer | WebFactory |
Plugin | WP Reset – Fastest WordPress Reset Plugin |
Version | 1.75 |
Comparing to | |
See all releases |
Code changes from version 1.70 to 1.75
- css/font/fontello.eot +0 -0
- css/font/fontello.svg +14 -0
- css/font/fontello.ttf +0 -0
- css/font/fontello.woff +0 -0
- css/font/fontello.woff2 +0 -0
- css/wp-reset.css +182 -15
- index.php +2 -0
- js/wp-reset.js +67 -51
- libs/diff.php +20 -20
- libs/diff/Renderer/Abstract.php +81 -81
- libs/diff/Renderer/Html/Array.php +225 -225
- libs/diff/Renderer/Html/Inline.php +143 -143
- libs/diff/Renderer/Html/SideBySide.php +162 -162
- libs/diff/Renderer/Text/Context.php +127 -127
- libs/diff/Renderer/Text/Unified.php +86 -86
- libs/diff/SequenceMatcher.php +741 -741
- libs/dumper.php +32 -32
- readme.txt +26 -9
- wp-reset-cli.php +4 -67
- wp-reset.php +220 -147
css/font/fontello.eot
ADDED
Binary file
|
css/font/fontello.svg
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?xml version="1.0" standalone="no"?>
|
2 |
+
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
3 |
+
<svg xmlns="http://www.w3.org/2000/svg">
|
4 |
+
<metadata>Copyright (C) 2019 by original authors @ fontello.com</metadata>
|
5 |
+
<defs>
|
6 |
+
<font id="fontello" horiz-adv-x="1000" >
|
7 |
+
<font-face font-family="fontello" font-weight="400" font-stretch="normal" units-per-em="1000" ascent="850" descent="-150" />
|
8 |
+
<missing-glyph horiz-adv-x="1000" />
|
9 |
+
<glyph glyph-name="doc-text-inv" unicode="" d="M819 584q8-7 16-20h-264v264q13-8 21-16z m-265-91h303v-589q0-23-15-38t-38-16h-750q-23 0-38 16t-16 38v892q0 23 16 38t38 16h446v-304q0-22 16-37t38-16z m89-411v36q0 8-5 13t-13 5h-393q-8 0-13-5t-5-13v-36q0-8 5-13t13-5h393q8 0 13 5t5 13z m0 143v36q0 8-5 13t-13 5h-393q-8 0-13-5t-5-13v-36q0-8 5-13t13-5h393q8 0 13 5t5 13z m0 143v36q0 7-5 12t-13 5h-393q-8 0-13-5t-5-12v-36q0-8 5-13t13-5h393q8 0 13 5t5 13z" horiz-adv-x="857.1" />
|
10 |
+
|
11 |
+
<glyph glyph-name="database" unicode="" d="M429 421q132 0 247 24t181 71v-95q0-38-57-71t-157-52-214-19-215 19-156 52-58 71v95q66-47 181-71t248-24z m0-428q132 0 247 24t181 71v-95q0-39-57-72t-157-52-214-19-215 19-156 52-58 72v95q66-47 181-71t248-24z m0 214q132 0 247 24t181 71v-95q0-38-57-71t-157-52-214-20-215 20-156 52-58 71v95q66-47 181-71t248-24z m0 643q116 0 214-19t157-52 57-72v-71q0-39-57-72t-157-52-214-19-215 19-156 52-58 72v71q0 39 58 72t156 52 215 19z" horiz-adv-x="857.1" />
|
12 |
+
</font>
|
13 |
+
</defs>
|
14 |
+
</svg>
|
css/font/fontello.ttf
ADDED
Binary file
|
css/font/fontello.woff
ADDED
Binary file
|
css/font/fontello.woff2
ADDED
Binary file
|
css/wp-reset.css
CHANGED
@@ -17,6 +17,21 @@
|
|
17 |
padding: 0;
|
18 |
}
|
19 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
#wpbody-content {
|
21 |
background: #f9fbfd;
|
22 |
}
|
@@ -47,6 +62,7 @@
|
|
47 |
#wpfooter {
|
48 |
padding: 20px;
|
49 |
border-top: 1px solid #e5e5e5;
|
|
|
50 |
}
|
51 |
|
52 |
#wpfooter a {
|
@@ -57,6 +73,74 @@
|
|
57 |
color: #ffb900;
|
58 |
}
|
59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
.tools_page_wp-reset #wp_reset_confirm {
|
61 |
vertical-align: top;
|
62 |
}
|
@@ -71,6 +155,12 @@
|
|
71 |
text-align: center;
|
72 |
}
|
73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
.tools_page_wp-reset .button.disabled {
|
75 |
pointer-events: none;
|
76 |
cursor: not-allowed;
|
@@ -82,14 +172,35 @@
|
|
82 |
border-radius: 0;
|
83 |
}
|
84 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
85 |
.tools_page_wp-reset .plain-list {
|
86 |
-
margin-top:
|
87 |
list-style-type: circle;
|
88 |
list-style-position: inside;
|
89 |
}
|
90 |
|
91 |
.tools_page_wp-reset .plain-list li {
|
92 |
-
text-indent: -
|
93 |
padding-left: 23px;
|
94 |
line-height: 23px;
|
95 |
margin: 0;
|
@@ -192,17 +303,18 @@
|
|
192 |
margin: -5px 0 0 0;
|
193 |
}
|
194 |
|
195 |
-
.tools_page_wp-reset .
|
196 |
text-decoration: none;
|
197 |
color: #444;
|
|
|
198 |
}
|
199 |
|
200 |
-
.tools_page_wp-reset .
|
201 |
color: #00a0d2;
|
202 |
}
|
203 |
|
204 |
.tools_page_wp-reset .card {
|
205 |
-
padding: 0 25px
|
206 |
max-width: 100%;
|
207 |
width: 100%;
|
208 |
margin: 0 0 35px 0;
|
@@ -223,12 +335,6 @@
|
|
223 |
padding-bottom: 0;
|
224 |
}
|
225 |
|
226 |
-
.tools_page_wp-reset .card.collapsed p,
|
227 |
-
.tools_page_wp-reset .card.collapsed b,
|
228 |
-
.tools_page_wp-reset .card.collapsed ul {
|
229 |
-
display: none;
|
230 |
-
}
|
231 |
-
|
232 |
.tools_page_wp-reset .card.collapsed h4 {
|
233 |
border: none;
|
234 |
}
|
@@ -246,10 +352,11 @@
|
|
246 |
|
247 |
.tools_page_wp-reset table td {
|
248 |
text-align: left;
|
249 |
-
padding:
|
|
|
250 |
}
|
251 |
|
252 |
-
.tools_page_wp-reset table tr:
|
253 |
background-color: #f9f9f9;
|
254 |
}
|
255 |
|
@@ -740,6 +847,7 @@
|
|
740 |
}
|
741 |
/* survey */
|
742 |
|
|
|
743 |
.webhooks-dialog .ui-dialog-titlebar {
|
744 |
background-color: rgb(241, 88, 42);
|
745 |
color: #fefefe;
|
@@ -756,7 +864,66 @@
|
|
756 |
.webhooks-dialog .plain-list li {
|
757 |
text-indent: -21px;
|
758 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
759 |
|
760 |
-
|
761 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
762 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
padding: 0;
|
18 |
}
|
19 |
|
20 |
+
.tools_page_wp-reset #loading-tabs {
|
21 |
+
padding-top: 80px;
|
22 |
+
text-align: center;
|
23 |
+
}
|
24 |
+
|
25 |
+
.tools_page_wp-reset #loading-tabs img {
|
26 |
+
width: 100px;
|
27 |
+
height: auto;
|
28 |
+
opacity: 0.4;
|
29 |
+
}
|
30 |
+
|
31 |
+
.tools_page_wp-reset .mb0 {
|
32 |
+
margin-bottom: 0;
|
33 |
+
}
|
34 |
+
|
35 |
#wpbody-content {
|
36 |
background: #f9fbfd;
|
37 |
}
|
62 |
#wpfooter {
|
63 |
padding: 20px;
|
64 |
border-top: 1px solid #e5e5e5;
|
65 |
+
background-color: #ffffff;
|
66 |
}
|
67 |
|
68 |
#wpfooter a {
|
73 |
color: #ffb900;
|
74 |
}
|
75 |
|
76 |
+
.tools_page_wp-reset .dropdown {
|
77 |
+
position: relative;
|
78 |
+
display: inline-block;
|
79 |
+
margin-right: 10px;
|
80 |
+
}
|
81 |
+
|
82 |
+
.tools_page_wp-reset .button.dropdown-toggle::after {
|
83 |
+
content: '\f140';
|
84 |
+
font-family: dashicons;
|
85 |
+
display: inline-block;
|
86 |
+
line-height: 1;
|
87 |
+
font-weight: 400;
|
88 |
+
font-style: normal;
|
89 |
+
text-decoration: inherit;
|
90 |
+
text-transform: none;
|
91 |
+
text-rendering: auto;
|
92 |
+
-webkit-font-smoothing: antialiased;
|
93 |
+
-moz-osx-font-smoothing: grayscale;
|
94 |
+
width: 20px;
|
95 |
+
height: 20px;
|
96 |
+
font-size: 20px;
|
97 |
+
vertical-align: text-top;
|
98 |
+
text-align: center;
|
99 |
+
}
|
100 |
+
|
101 |
+
.tools_page_wp-reset .dropdown .dropdown-menu {
|
102 |
+
position: absolute;
|
103 |
+
top: 100%;
|
104 |
+
left: 0;
|
105 |
+
z-index: 1000;
|
106 |
+
display: none;
|
107 |
+
float: left;
|
108 |
+
min-width: 10rem;
|
109 |
+
padding: 0.5rem 0;
|
110 |
+
margin: 0;
|
111 |
+
color: #212529;
|
112 |
+
text-align: left;
|
113 |
+
list-style: none;
|
114 |
+
background-color: #fff;
|
115 |
+
background-clip: padding-box;
|
116 |
+
border: 1px solid rgba(0, 0, 0, 0.15);
|
117 |
+
}
|
118 |
+
|
119 |
+
.tools_page_wp-reset .dropdown .dropdown-menu.show {
|
120 |
+
display: block;
|
121 |
+
}
|
122 |
+
|
123 |
+
.tools_page_wp-reset .dropdown-menu .dropdown-item {
|
124 |
+
display: block;
|
125 |
+
width: 100%;
|
126 |
+
padding: 0.25rem 1.5rem;
|
127 |
+
clear: both;
|
128 |
+
color: #212529;
|
129 |
+
text-align: inherit;
|
130 |
+
white-space: nowrap;
|
131 |
+
background-color: transparent;
|
132 |
+
border: 0;
|
133 |
+
text-decoration: none;
|
134 |
+
box-sizing: border-box;
|
135 |
+
}
|
136 |
+
|
137 |
+
.tools_page_wp-reset .dropdown-menu .dropdown-item:focus,
|
138 |
+
.tools_page_wp-reset .dropdown-item:hover {
|
139 |
+
color: #16181b;
|
140 |
+
text-decoration: none;
|
141 |
+
background-color: #f8f9fa;
|
142 |
+
}
|
143 |
+
|
144 |
.tools_page_wp-reset #wp_reset_confirm {
|
145 |
vertical-align: top;
|
146 |
}
|
155 |
text-align: center;
|
156 |
}
|
157 |
|
158 |
+
.tools_page_wp-reset .half {
|
159 |
+
width: 50%;
|
160 |
+
display: inline-block;
|
161 |
+
vertical-align: top;
|
162 |
+
}
|
163 |
+
|
164 |
.tools_page_wp-reset .button.disabled {
|
165 |
pointer-events: none;
|
166 |
cursor: not-allowed;
|
172 |
border-radius: 0;
|
173 |
}
|
174 |
|
175 |
+
.tools_page_wp-reset .button,
|
176 |
+
.tools_page_wp-reset .button-secondary {
|
177 |
+
color: #555;
|
178 |
+
border-color: #ccc;
|
179 |
+
background: #f7f7f7;
|
180 |
+
box-shadow: 0 1px 0 #ccc;
|
181 |
+
}
|
182 |
+
|
183 |
+
.tools_page_wp-reset .button-secondary:focus, .tools_page_wp-reset .button-secondary:hover, .tools_page_wp-reset .button.focus, .tools_page_wp-reset .button.hover, .tools_page_wp-reset .button:focus, .tools_page_wp-reset .button:hover {
|
184 |
+
background: #fafafa;
|
185 |
+
border-color: #999;
|
186 |
+
color: #23282d;
|
187 |
+
}
|
188 |
+
|
189 |
+
.tools_page_wp-reset .button:not(.button-primary):hover {
|
190 |
+
background: #f1f1f1;
|
191 |
+
}
|
192 |
+
.tools_page_wp-reset .button:not(.button-primary) {
|
193 |
+
background: #ffffff;
|
194 |
+
}
|
195 |
+
|
196 |
.tools_page_wp-reset .plain-list {
|
197 |
+
margin-top: 10px;
|
198 |
list-style-type: circle;
|
199 |
list-style-position: inside;
|
200 |
}
|
201 |
|
202 |
.tools_page_wp-reset .plain-list li {
|
203 |
+
text-indent: -20px;
|
204 |
padding-left: 23px;
|
205 |
line-height: 23px;
|
206 |
margin: 0;
|
303 |
margin: -5px 0 0 0;
|
304 |
}
|
305 |
|
306 |
+
.tools_page_wp-reset .card-header-right a:not(.button) {
|
307 |
text-decoration: none;
|
308 |
color: #444;
|
309 |
+
margin-left: 5px;
|
310 |
}
|
311 |
|
312 |
+
.tools_page_wp-reset .card-header-right a:hover:not(.button) {
|
313 |
color: #00a0d2;
|
314 |
}
|
315 |
|
316 |
.tools_page_wp-reset .card {
|
317 |
+
padding: 0 25px 20px 25px;
|
318 |
max-width: 100%;
|
319 |
width: 100%;
|
320 |
margin: 0 0 35px 0;
|
335 |
padding-bottom: 0;
|
336 |
}
|
337 |
|
|
|
|
|
|
|
|
|
|
|
|
|
338 |
.tools_page_wp-reset .card.collapsed h4 {
|
339 |
border: none;
|
340 |
}
|
352 |
|
353 |
.tools_page_wp-reset table td {
|
354 |
text-align: left;
|
355 |
+
padding: 20px 10px;
|
356 |
+
border-bottom: thin solid #999;
|
357 |
}
|
358 |
|
359 |
+
.tools_page_wp-reset table tr:hover td {
|
360 |
background-color: #f9f9f9;
|
361 |
}
|
362 |
|
847 |
}
|
848 |
/* survey */
|
849 |
|
850 |
+
/* webhooks dialog */
|
851 |
.webhooks-dialog .ui-dialog-titlebar {
|
852 |
background-color: rgb(241, 88, 42);
|
853 |
color: #fefefe;
|
864 |
.webhooks-dialog .plain-list li {
|
865 |
text-indent: -21px;
|
866 |
}
|
867 |
+
/* webhooks dialog */
|
868 |
+
|
869 |
+
/* Fontello */
|
870 |
+
@font-face {
|
871 |
+
font-family: 'fontello';
|
872 |
+
src: url('./font/fontello.eot?91671913');
|
873 |
+
src: url('./font/fontello.eot?91671913#iefix') format('embedded-opentype'),
|
874 |
+
url('./font/fontello.woff2?91671913') format('woff2'), url('./font/fontello.woff?91671913') format('woff'),
|
875 |
+
url('./font/fontello.ttf?91671913') format('truetype'), url('./font/fontello.svg?91671913#fontello') format('svg');
|
876 |
+
font-weight: normal;
|
877 |
+
font-style: normal;
|
878 |
+
}
|
879 |
+
/* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */
|
880 |
+
/* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */
|
881 |
+
/*
|
882 |
+
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
883 |
+
@font-face {
|
884 |
+
font-family: 'fontello';
|
885 |
+
src: url('./font/fontello.svg?91671913#fontello') format('svg');
|
886 |
+
}
|
887 |
+
}
|
888 |
+
*/
|
889 |
|
890 |
+
[class^='icon-']:before,
|
891 |
+
[class*=' icon-']:before {
|
892 |
+
font-family: 'fontello';
|
893 |
+
font-style: normal;
|
894 |
+
font-weight: normal;
|
895 |
+
display: inline-block;
|
896 |
+
text-decoration: inherit;
|
897 |
+
width: 1em;
|
898 |
+
margin-right: 0.2em;
|
899 |
+
text-align: center;
|
900 |
+
/* opacity: .8; */
|
901 |
+
|
902 |
+
/* For safety - reset parent styles, that can break glyph codes*/
|
903 |
+
font-variant: normal;
|
904 |
+
text-transform: none;
|
905 |
+
|
906 |
+
/* fix buttons height, for twitter bootstrap */
|
907 |
+
line-height: 1em;
|
908 |
+
|
909 |
+
/* Animation center compensation - margins should be symmetric */
|
910 |
+
/* remove if not needed */
|
911 |
+
margin-left: 0.2em;
|
912 |
+
|
913 |
+
/* you can be more comfortable with increased icons size */
|
914 |
+
/* font-size: 120%; */
|
915 |
+
|
916 |
+
/* Font smoothing. That was taken from TWBS */
|
917 |
+
-webkit-font-smoothing: antialiased;
|
918 |
+
-moz-osx-font-smoothing: grayscale;
|
919 |
+
|
920 |
+
/* Uncomment for 3D effect */
|
921 |
+
/* text-shadow: 1px 1px 1px rgba(127, 127, 127, 0.3); */
|
922 |
}
|
923 |
+
|
924 |
+
.icon-doc-text-inv:before {
|
925 |
+
content: '\f15c';
|
926 |
+
} /* '' */
|
927 |
+
.icon-database:before {
|
928 |
+
content: '\f1c0';
|
929 |
+
} /* '' */
|
index.php
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// Silence is golden
|
js/wp-reset.js
CHANGED
@@ -8,6 +8,9 @@ jQuery(document).ready(function($) {
|
|
8 |
// init tabs
|
9 |
$('#wp-reset-tabs')
|
10 |
.tabs({
|
|
|
|
|
|
|
11 |
activate: function(event, ui) {
|
12 |
localStorage.setItem('wp-reset-tabs', $('#wp-reset-tabs').tabs('option', 'active'));
|
13 |
},
|
@@ -27,9 +30,48 @@ jQuery(document).ready(function($) {
|
|
27 |
$.scrollTo('#' + target, 500, { offset: { top: -50, left: 0 } });
|
28 |
}
|
29 |
|
|
|
30 |
return false;
|
31 |
}); // jump to tab/anchor helper
|
32 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
// delete transients
|
34 |
$('.tools_page_wp-reset').on('click', '#delete-transients', 'click', function(e) {
|
35 |
e.preventDefault();
|
@@ -102,53 +144,6 @@ jQuery(document).ready(function($) {
|
|
102 |
return false;
|
103 |
}); // delete htaccess file
|
104 |
|
105 |
-
// create&download backup
|
106 |
-
$('.tools_page_wp-reset').on('click', '.download-backup', 'click', function(e) {
|
107 |
-
e.preventDefault();
|
108 |
-
button = this;
|
109 |
-
|
110 |
-
block_ui(wp_reset.creating_backup);
|
111 |
-
$.get({
|
112 |
-
url: ajaxurl,
|
113 |
-
data: {
|
114 |
-
action: 'wp_reset_run_tool',
|
115 |
-
_ajax_nonce: wp_reset.nonce_run_tool,
|
116 |
-
tool: 'download_backup'
|
117 |
-
}
|
118 |
-
})
|
119 |
-
.always(function(data) {
|
120 |
-
swal.close();
|
121 |
-
})
|
122 |
-
.done(function(data) {
|
123 |
-
if (data.success) {
|
124 |
-
$.ajax({
|
125 |
-
type: 'HEAD',
|
126 |
-
url: data.data,
|
127 |
-
success: function() {
|
128 |
-
window.location = data.data;
|
129 |
-
},
|
130 |
-
error: function() {
|
131 |
-
swal({
|
132 |
-
type: 'error',
|
133 |
-
title: wp_reset.backup_not_accessible,
|
134 |
-
html: wp_reset.backup_not_accessible_details.replace('%url%', data.data)
|
135 |
-
});
|
136 |
-
}
|
137 |
-
});
|
138 |
-
} else {
|
139 |
-
swal({
|
140 |
-
type: 'error',
|
141 |
-
title: wp_reset.documented_error + ' ' + data.data
|
142 |
-
});
|
143 |
-
}
|
144 |
-
})
|
145 |
-
.fail(function(data) {
|
146 |
-
swal({ type: 'error', title: wp_reset.undocumented_error });
|
147 |
-
});
|
148 |
-
|
149 |
-
return false;
|
150 |
-
}); // create&download backup
|
151 |
-
|
152 |
// compare snapshot
|
153 |
$('#wpr-snapshots').on('click', '.compare-snapshot', 'click', function(e) {
|
154 |
e.preventDefault();
|
@@ -260,12 +255,14 @@ jQuery(document).ready(function($) {
|
|
260 |
$('.tools_page_wp-reset').on('click', '.create-new-snapshot', 'click', function(e) {
|
261 |
e.preventDefault();
|
262 |
button = $('#create-new-snapshot-primary');
|
|
|
263 |
|
264 |
swal({
|
265 |
title: $(button).data('title'),
|
266 |
type: 'question',
|
267 |
text: $(button).data('text'),
|
268 |
input: 'text',
|
|
|
269 |
inputPlaceholder: $(button).data('placeholder'),
|
270 |
showCancelButton: true,
|
271 |
focusConfirm: false,
|
@@ -329,6 +326,8 @@ jQuery(document).ready(function($) {
|
|
329 |
function run_tool(button, tool_name, extra_data) {
|
330 |
var confirm_title = $(button).data('confirm-title') || wp_reset.confirm_title;
|
331 |
|
|
|
|
|
332 |
confirm_action(
|
333 |
confirm_title,
|
334 |
$(button).data('text-confirm'),
|
@@ -473,7 +472,7 @@ jQuery(document).ready(function($) {
|
|
473 |
}); // reset submit
|
474 |
|
475 |
// collapse / expand card
|
476 |
-
$('.
|
477 |
e.preventDefault();
|
478 |
|
479 |
card = $(this)
|
@@ -484,6 +483,16 @@ jQuery(document).ready(function($) {
|
|
484 |
.toggleClass('dashicons-arrow-down-alt2');
|
485 |
$(this).blur();
|
486 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
487 |
cards = localStorage.getItem('wp-reset-cards');
|
488 |
if (cards == null) {
|
489 |
cards = new Object();
|
@@ -491,10 +500,12 @@ jQuery(document).ready(function($) {
|
|
491 |
cards = JSON.parse(cards);
|
492 |
}
|
493 |
|
|
|
|
|
494 |
if (card.hasClass('collapsed')) {
|
495 |
-
cards[
|
496 |
} else {
|
497 |
-
cards[
|
498 |
}
|
499 |
localStorage.setItem('wp-reset-cards', JSON.stringify(cards));
|
500 |
|
@@ -508,7 +519,7 @@ jQuery(document).ready(function($) {
|
|
508 |
}
|
509 |
$.each(cards, function(card_name, card_value) {
|
510 |
if (card_value == 'collapsed') {
|
511 |
-
$('a.toggle-card', '#' + card_name).trigger('click');
|
512 |
}
|
513 |
});
|
514 |
|
@@ -680,3 +691,8 @@ function wpr_fix_dialog_close(event, ui) {
|
|
680 |
jQuery('#' + event.target.id).dialog('close');
|
681 |
});
|
682 |
} // wpr_fix_dialog_close
|
|
|
|
|
|
|
|
|
|
8 |
// init tabs
|
9 |
$('#wp-reset-tabs')
|
10 |
.tabs({
|
11 |
+
create: function() {
|
12 |
+
$('#loading-tabs').remove();
|
13 |
+
},
|
14 |
activate: function(event, ui) {
|
15 |
localStorage.setItem('wp-reset-tabs', $('#wp-reset-tabs').tabs('option', 'active'));
|
16 |
},
|
30 |
$.scrollTo('#' + target, 500, { offset: { top: -50, left: 0 } });
|
31 |
}
|
32 |
|
33 |
+
$(this).blur();
|
34 |
return false;
|
35 |
}); // jump to tab/anchor helper
|
36 |
|
37 |
+
// helper for scrolling to anchor
|
38 |
+
$('.tools_page_wp-reset').on('click', '.scrollto', function(e) {
|
39 |
+
e.preventDefault();
|
40 |
+
|
41 |
+
// get the link anchor and scroll to it
|
42 |
+
target = this.href.split('#')[1];
|
43 |
+
if (target) {
|
44 |
+
$.scrollTo('#' + target, 500, { offset: { top: -50, left: 0 } });
|
45 |
+
}
|
46 |
+
|
47 |
+
$(this).blur();
|
48 |
+
return false;
|
49 |
+
}); // scroll to anchor helper
|
50 |
+
|
51 |
+
// toggle button dropdown menu
|
52 |
+
$('.tools_page_wp-reset').on('click', '.button.dropdown-toggle', function(e) {
|
53 |
+
e.preventDefault();
|
54 |
+
|
55 |
+
parent_dropdown = $(this).parent('.dropdown');
|
56 |
+
sibling_menu = $(this).siblings('.dropdown-menu');
|
57 |
+
|
58 |
+
$('.dropdown')
|
59 |
+
.not(parent_dropdown)
|
60 |
+
.removeClass('show');
|
61 |
+
$('.dropdown-menu')
|
62 |
+
.not(sibling_menu)
|
63 |
+
.removeClass('show');
|
64 |
+
|
65 |
+
$(parent_dropdown).toggleClass('show');
|
66 |
+
$(sibling_menu).toggleClass('show');
|
67 |
+
|
68 |
+
return false;
|
69 |
+
}); // toggle button dropdown menu
|
70 |
+
|
71 |
+
$(document).on('click', ':not(.dropdown-toggle), .dropdown-item', function() {
|
72 |
+
wpr_close_dropdowns();
|
73 |
+
});
|
74 |
+
|
75 |
// delete transients
|
76 |
$('.tools_page_wp-reset').on('click', '#delete-transients', 'click', function(e) {
|
77 |
e.preventDefault();
|
144 |
return false;
|
145 |
}); // delete htaccess file
|
146 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
147 |
// compare snapshot
|
148 |
$('#wpr-snapshots').on('click', '.compare-snapshot', 'click', function(e) {
|
149 |
e.preventDefault();
|
255 |
$('.tools_page_wp-reset').on('click', '.create-new-snapshot', 'click', function(e) {
|
256 |
e.preventDefault();
|
257 |
button = $('#create-new-snapshot-primary');
|
258 |
+
description = $(this).data('description') || '';
|
259 |
|
260 |
swal({
|
261 |
title: $(button).data('title'),
|
262 |
type: 'question',
|
263 |
text: $(button).data('text'),
|
264 |
input: 'text',
|
265 |
+
inputValue: description,
|
266 |
inputPlaceholder: $(button).data('placeholder'),
|
267 |
showCancelButton: true,
|
268 |
focusConfirm: false,
|
326 |
function run_tool(button, tool_name, extra_data) {
|
327 |
var confirm_title = $(button).data('confirm-title') || wp_reset.confirm_title;
|
328 |
|
329 |
+
wpr_close_dropdowns();
|
330 |
+
|
331 |
confirm_action(
|
332 |
confirm_title,
|
333 |
$(button).data('text-confirm'),
|
472 |
}); // reset submit
|
473 |
|
474 |
// collapse / expand card
|
475 |
+
$('.tools_page_wp-reset').on('click', '.toggle-card', function(e, skip_anim) {
|
476 |
e.preventDefault();
|
477 |
|
478 |
card = $(this)
|
483 |
.toggleClass('dashicons-arrow-down-alt2');
|
484 |
$(this).blur();
|
485 |
|
486 |
+
if (typeof skip_anim != 'undefined' && skip_anim) {
|
487 |
+
$(card)
|
488 |
+
.find('.card-body')
|
489 |
+
.toggle();
|
490 |
+
} else {
|
491 |
+
$(card)
|
492 |
+
.find('.card-body')
|
493 |
+
.slideToggle(500);
|
494 |
+
}
|
495 |
+
|
496 |
cards = localStorage.getItem('wp-reset-cards');
|
497 |
if (cards == null) {
|
498 |
cards = new Object();
|
500 |
cards = JSON.parse(cards);
|
501 |
}
|
502 |
|
503 |
+
card_id = card.attr('id') || $('h4', card).attr('id') || '';
|
504 |
+
|
505 |
if (card.hasClass('collapsed')) {
|
506 |
+
cards[card_id] = 'collapsed';
|
507 |
} else {
|
508 |
+
cards[card_id] = 'expanded';
|
509 |
}
|
510 |
localStorage.setItem('wp-reset-cards', JSON.stringify(cards));
|
511 |
|
519 |
}
|
520 |
$.each(cards, function(card_name, card_value) {
|
521 |
if (card_value == 'collapsed') {
|
522 |
+
$('a.toggle-card', '#' + card_name).trigger('click', true);
|
523 |
}
|
524 |
});
|
525 |
|
691 |
jQuery('#' + event.target.id).dialog('close');
|
692 |
});
|
693 |
} // wpr_fix_dialog_close
|
694 |
+
|
695 |
+
function wpr_close_dropdowns() {
|
696 |
+
jQuery('.dropdown').removeClass('show');
|
697 |
+
jQuery('.dropdown-menu').removeClass('show');
|
698 |
+
} // wpr_close_dropdowns
|
libs/diff.php
CHANGED
@@ -8,10 +8,10 @@
|
|
8 |
* PHP version 5
|
9 |
*
|
10 |
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
11 |
-
*
|
12 |
* All rights reserved.
|
13 |
-
*
|
14 |
-
* Redistribution and use in source and binary forms, with or without
|
15 |
* modification, are permitted provided that the following conditions are met:
|
16 |
*
|
17 |
* - Redistributions of source code must retain the above copyright notice,
|
@@ -19,20 +19,20 @@
|
|
19 |
* - Redistributions in binary form must reproduce the above copyright notice,
|
20 |
* this list of conditions and the following disclaimer in the documentation
|
21 |
* and/or other materials provided with the distribution.
|
22 |
-
* - Neither the name of the Chris Boulton nor the names of its contributors
|
23 |
-
* may be used to endorse or promote products derived from this software
|
24 |
* without specific prior written permission.
|
25 |
*
|
26 |
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
27 |
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
28 |
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
29 |
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
30 |
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
31 |
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
32 |
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
33 |
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
34 |
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
35 |
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
36 |
* POSSIBILITY OF SUCH DAMAGE.
|
37 |
*
|
38 |
* @package Diff
|
@@ -43,7 +43,7 @@
|
|
43 |
* @link http://github.com/chrisboulton/php-diff
|
44 |
*/
|
45 |
|
46 |
-
class
|
47 |
{
|
48 |
/**
|
49 |
* @var array The "old" sequence to use as the basis for the comparison.
|
@@ -98,7 +98,7 @@ class Diff
|
|
98 |
* @param object $renderer An instance of the rendering object to use for generating the diff.
|
99 |
* @return mixed The generated diff. Exact return value depends on the rendered.
|
100 |
*/
|
101 |
-
public function render(
|
102 |
{
|
103 |
$renderer->diff = $this;
|
104 |
return $renderer->render();
|
@@ -171,9 +171,9 @@ class Diff
|
|
171 |
return $this->groupedCodes;
|
172 |
}
|
173 |
|
174 |
-
require_once dirname(__FILE__).'/
|
175 |
-
$sequenceMatcher = new
|
176 |
$this->groupedCodes = $sequenceMatcher->getGroupedOpcodes($this->options['context']);
|
177 |
return $this->groupedCodes;
|
178 |
}
|
179 |
-
}
|
8 |
* PHP version 5
|
9 |
*
|
10 |
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
11 |
+
*
|
12 |
* All rights reserved.
|
13 |
+
*
|
14 |
+
* Redistribution and use in source and binary forms, with or without
|
15 |
* modification, are permitted provided that the following conditions are met:
|
16 |
*
|
17 |
* - Redistributions of source code must retain the above copyright notice,
|
19 |
* - Redistributions in binary form must reproduce the above copyright notice,
|
20 |
* this list of conditions and the following disclaimer in the documentation
|
21 |
* and/or other materials provided with the distribution.
|
22 |
+
* - Neither the name of the Chris Boulton nor the names of its contributors
|
23 |
+
* may be used to endorse or promote products derived from this software
|
24 |
* without specific prior written permission.
|
25 |
*
|
26 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
27 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
28 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
29 |
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
30 |
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
31 |
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
32 |
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
33 |
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
34 |
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
35 |
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
36 |
* POSSIBILITY OF SUCH DAMAGE.
|
37 |
*
|
38 |
* @package Diff
|
43 |
* @link http://github.com/chrisboulton/php-diff
|
44 |
*/
|
45 |
|
46 |
+
class WPR_Diff
|
47 |
{
|
48 |
/**
|
49 |
* @var array The "old" sequence to use as the basis for the comparison.
|
98 |
* @param object $renderer An instance of the rendering object to use for generating the diff.
|
99 |
* @return mixed The generated diff. Exact return value depends on the rendered.
|
100 |
*/
|
101 |
+
public function render(WPR_Diff_Renderer_Html_SideBySide $renderer)
|
102 |
{
|
103 |
$renderer->diff = $this;
|
104 |
return $renderer->render();
|
171 |
return $this->groupedCodes;
|
172 |
}
|
173 |
|
174 |
+
require_once dirname(__FILE__).'/diff/SequenceMatcher.php';
|
175 |
+
$sequenceMatcher = new WPR_Diff_SequenceMatcher($this->a, $this->b, null, $this->options);
|
176 |
$this->groupedCodes = $sequenceMatcher->getGroupedOpcodes($this->options['context']);
|
177 |
return $this->groupedCodes;
|
178 |
}
|
179 |
+
}
|
libs/diff/Renderer/Abstract.php
CHANGED
@@ -1,82 +1,82 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Abstract class for diff renderers in PHP DiffLib.
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
-
*
|
9 |
-
* All rights reserved.
|
10 |
-
*
|
11 |
-
* Redistribution and use in source and binary forms, with or without
|
12 |
-
* modification, are permitted provided that the following conditions are met:
|
13 |
-
*
|
14 |
-
* - Redistributions of source code must retain the above copyright notice,
|
15 |
-
* this list of conditions and the following disclaimer.
|
16 |
-
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
-
* this list of conditions and the following disclaimer in the documentation
|
18 |
-
* and/or other materials provided with the distribution.
|
19 |
-
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
-
* may be used to endorse or promote products derived from this software
|
21 |
-
* without specific prior written permission.
|
22 |
-
*
|
23 |
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
-
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
-
*
|
35 |
-
* @package DiffLib
|
36 |
-
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
-
* @copyright (c) 2009 Chris Boulton
|
38 |
-
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
-
* @version 1.1
|
40 |
-
* @link http://github.com/chrisboulton/php-diff
|
41 |
-
*/
|
42 |
-
|
43 |
-
abstract class
|
44 |
-
{
|
45 |
-
/**
|
46 |
-
* @var object Instance of the diff class that this renderer is generating the rendered diff for.
|
47 |
-
*/
|
48 |
-
public $diff;
|
49 |
-
|
50 |
-
/**
|
51 |
-
* @var array Array of the default options that apply to this renderer.
|
52 |
-
*/
|
53 |
-
protected $defaultOptions = array();
|
54 |
-
|
55 |
-
/**
|
56 |
-
* @var array Array containing the user applied and merged default options for the renderer.
|
57 |
-
*/
|
58 |
-
protected $options = array();
|
59 |
-
|
60 |
-
/**
|
61 |
-
* The constructor. Instantiates the rendering engine and if options are passed,
|
62 |
-
* sets the options for the renderer.
|
63 |
-
*
|
64 |
-
* @param array $options Optionally, an array of the options for the renderer.
|
65 |
-
*/
|
66 |
-
public function __construct(array $options = array())
|
67 |
-
{
|
68 |
-
$this->setOptions($options);
|
69 |
-
}
|
70 |
-
|
71 |
-
/**
|
72 |
-
* Set the options of the renderer to those supplied in the passed in array.
|
73 |
-
* Options are merged with the default to ensure that there aren't any missing
|
74 |
-
* options.
|
75 |
-
*
|
76 |
-
* @param array $options Array of options to set.
|
77 |
-
*/
|
78 |
-
public function setOptions(array $options)
|
79 |
-
{
|
80 |
-
$this->options = array_merge($this->defaultOptions, $options);
|
81 |
-
}
|
82 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Abstract class for diff renderers in PHP DiffLib.
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
+
*
|
9 |
+
* All rights reserved.
|
10 |
+
*
|
11 |
+
* Redistribution and use in source and binary forms, with or without
|
12 |
+
* modification, are permitted provided that the following conditions are met:
|
13 |
+
*
|
14 |
+
* - Redistributions of source code must retain the above copyright notice,
|
15 |
+
* this list of conditions and the following disclaimer.
|
16 |
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
+
* this list of conditions and the following disclaimer in the documentation
|
18 |
+
* and/or other materials provided with the distribution.
|
19 |
+
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
+
* may be used to endorse or promote products derived from this software
|
21 |
+
* without specific prior written permission.
|
22 |
+
*
|
23 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
+
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
+
*
|
35 |
+
* @package DiffLib
|
36 |
+
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
+
* @copyright (c) 2009 Chris Boulton
|
38 |
+
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
+
* @version 1.1
|
40 |
+
* @link http://github.com/chrisboulton/php-diff
|
41 |
+
*/
|
42 |
+
|
43 |
+
abstract class WPR_Diff_Renderer_Abstract
|
44 |
+
{
|
45 |
+
/**
|
46 |
+
* @var object Instance of the diff class that this renderer is generating the rendered diff for.
|
47 |
+
*/
|
48 |
+
public $diff;
|
49 |
+
|
50 |
+
/**
|
51 |
+
* @var array Array of the default options that apply to this renderer.
|
52 |
+
*/
|
53 |
+
protected $defaultOptions = array();
|
54 |
+
|
55 |
+
/**
|
56 |
+
* @var array Array containing the user applied and merged default options for the renderer.
|
57 |
+
*/
|
58 |
+
protected $options = array();
|
59 |
+
|
60 |
+
/**
|
61 |
+
* The constructor. Instantiates the rendering engine and if options are passed,
|
62 |
+
* sets the options for the renderer.
|
63 |
+
*
|
64 |
+
* @param array $options Optionally, an array of the options for the renderer.
|
65 |
+
*/
|
66 |
+
public function __construct(array $options = array())
|
67 |
+
{
|
68 |
+
$this->setOptions($options);
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Set the options of the renderer to those supplied in the passed in array.
|
73 |
+
* Options are merged with the default to ensure that there aren't any missing
|
74 |
+
* options.
|
75 |
+
*
|
76 |
+
* @param array $options Array of options to set.
|
77 |
+
*/
|
78 |
+
public function setOptions(array $options)
|
79 |
+
{
|
80 |
+
$this->options = array_merge($this->defaultOptions, $options);
|
81 |
+
}
|
82 |
}
|
libs/diff/Renderer/Html/Array.php
CHANGED
@@ -1,225 +1,225 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Base renderer for rendering HTML based diffs for PHP DiffLib.
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
-
*
|
9 |
-
* All rights reserved.
|
10 |
-
*
|
11 |
-
* Redistribution and use in source and binary forms, with or without
|
12 |
-
* modification, are permitted provided that the following conditions are met:
|
13 |
-
*
|
14 |
-
* - Redistributions of source code must retain the above copyright notice,
|
15 |
-
* this list of conditions and the following disclaimer.
|
16 |
-
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
-
* this list of conditions and the following disclaimer in the documentation
|
18 |
-
* and/or other materials provided with the distribution.
|
19 |
-
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
-
* may be used to endorse or promote products derived from this software
|
21 |
-
* without specific prior written permission.
|
22 |
-
*
|
23 |
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
-
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
-
*
|
35 |
-
* @package DiffLib
|
36 |
-
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
-
* @copyright (c) 2009 Chris Boulton
|
38 |
-
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
-
* @version 1.1
|
40 |
-
* @link http://github.com/chrisboulton/php-diff
|
41 |
-
*/
|
42 |
-
|
43 |
-
require_once dirname(__FILE__).'/../Abstract.php';
|
44 |
-
|
45 |
-
class
|
46 |
-
{
|
47 |
-
/**
|
48 |
-
* @var array Array of the default options that apply to this renderer.
|
49 |
-
*/
|
50 |
-
protected $defaultOptions = array(
|
51 |
-
'tabSize' => 4
|
52 |
-
);
|
53 |
-
|
54 |
-
/**
|
55 |
-
* Render and return an array structure suitable for generating HTML
|
56 |
-
* based differences. Generally called by subclasses that generate a
|
57 |
-
* HTML based diff and return an array of the changes to show in the diff.
|
58 |
-
*
|
59 |
-
* @return array An array of the generated chances, suitable for presentation in HTML.
|
60 |
-
*/
|
61 |
-
public function render()
|
62 |
-
{
|
63 |
-
// As we'll be modifying a & b to include our change markers,
|
64 |
-
// we need to get the contents and store them here. That way
|
65 |
-
// we're not going to destroy the original data
|
66 |
-
$a = $this->diff->getA();
|
67 |
-
$b = $this->diff->getB();
|
68 |
-
|
69 |
-
$changes = array();
|
70 |
-
$opCodes = $this->diff->getGroupedOpcodes();
|
71 |
-
foreach($opCodes as $group) {
|
72 |
-
$blocks = array();
|
73 |
-
$lastTag = null;
|
74 |
-
$lastBlock = 0;
|
75 |
-
foreach($group as $code) {
|
76 |
-
list($tag, $i1, $i2, $j1, $j2) = $code;
|
77 |
-
|
78 |
-
if($tag == 'replace' && $i2 - $i1 == $j2 - $j1) {
|
79 |
-
for($i = 0; $i < ($i2 - $i1); ++$i) {
|
80 |
-
$fromLine = $a[$i1 + $i];
|
81 |
-
$toLine = $b[$j1 + $i];
|
82 |
-
|
83 |
-
list($start, $end) = $this->getChangeExtent($fromLine, $toLine);
|
84 |
-
if($start != 0 || $end != 0) {
|
85 |
-
$last = $end + strlen($fromLine);
|
86 |
-
$fromLine = substr_replace($fromLine, "\0", $start, 0);
|
87 |
-
$fromLine = substr_replace($fromLine, "\1", $last + 1, 0);
|
88 |
-
$last = $end + strlen($toLine);
|
89 |
-
$toLine = substr_replace($toLine, "\0", $start, 0);
|
90 |
-
$toLine = substr_replace($toLine, "\1", $last + 1, 0);
|
91 |
-
$a[$i1 + $i] = $fromLine;
|
92 |
-
$b[$j1 + $i] = $toLine;
|
93 |
-
}
|
94 |
-
}
|
95 |
-
}
|
96 |
-
|
97 |
-
if($tag != $lastTag) {
|
98 |
-
$blocks[] = array(
|
99 |
-
'tag' => $tag,
|
100 |
-
'base' => array(
|
101 |
-
'offset' => $i1,
|
102 |
-
'lines' => array()
|
103 |
-
),
|
104 |
-
'changed' => array(
|
105 |
-
'offset' => $j1,
|
106 |
-
'lines' => array()
|
107 |
-
)
|
108 |
-
);
|
109 |
-
$lastBlock = count($blocks)-1;
|
110 |
-
}
|
111 |
-
|
112 |
-
$lastTag = $tag;
|
113 |
-
|
114 |
-
if($tag == 'equal') {
|
115 |
-
$lines = array_slice($a, $i1, ($i2 - $i1));
|
116 |
-
$blocks[$lastBlock]['base']['lines'] += $this->formatLines($lines);
|
117 |
-
$lines = array_slice($b, $j1, ($j2 - $j1));
|
118 |
-
$blocks[$lastBlock]['changed']['lines'] += $this->formatLines($lines);
|
119 |
-
}
|
120 |
-
else {
|
121 |
-
if($tag == 'replace' || $tag == 'delete') {
|
122 |
-
$lines = array_slice($a, $i1, ($i2 - $i1));
|
123 |
-
$lines = $this->formatLines($lines);
|
124 |
-
$lines = str_replace(array("\0", "\1"), array('<del>', '</del>'), $lines);
|
125 |
-
$blocks[$lastBlock]['base']['lines'] += $lines;
|
126 |
-
}
|
127 |
-
|
128 |
-
if($tag == 'replace' || $tag == 'insert') {
|
129 |
-
$lines = array_slice($b, $j1, ($j2 - $j1));
|
130 |
-
$lines = $this->formatLines($lines);
|
131 |
-
$lines = str_replace(array("\0", "\1"), array('<ins>', '</ins>'), $lines);
|
132 |
-
$blocks[$lastBlock]['changed']['lines'] += $lines;
|
133 |
-
}
|
134 |
-
}
|
135 |
-
}
|
136 |
-
$changes[] = $blocks;
|
137 |
-
}
|
138 |
-
return $changes;
|
139 |
-
}
|
140 |
-
|
141 |
-
/**
|
142 |
-
* Given two strings, determine where the changes in the two strings
|
143 |
-
* begin, and where the changes in the two strings end.
|
144 |
-
*
|
145 |
-
* @param string $fromLine The first string.
|
146 |
-
* @param string $toLine The second string.
|
147 |
-
* @return array Array containing the starting position (0 by default) and the ending position (-1 by default)
|
148 |
-
*/
|
149 |
-
private function getChangeExtent($fromLine, $toLine)
|
150 |
-
{
|
151 |
-
$start = 0;
|
152 |
-
$limit = min(strlen($fromLine), strlen($toLine));
|
153 |
-
while($start < $limit && $fromLine{$start} == $toLine{$start}) {
|
154 |
-
++$start;
|
155 |
-
}
|
156 |
-
$end = -1;
|
157 |
-
$limit = $limit - $start;
|
158 |
-
while(-$end <= $limit && substr($fromLine, $end, 1) == substr($toLine, $end, 1)) {
|
159 |
-
--$end;
|
160 |
-
}
|
161 |
-
return array(
|
162 |
-
$start,
|
163 |
-
$end + 1
|
164 |
-
);
|
165 |
-
}
|
166 |
-
|
167 |
-
/**
|
168 |
-
* Format a series of lines suitable for output in a HTML rendered diff.
|
169 |
-
* This involves replacing tab characters with spaces, making the HTML safe
|
170 |
-
* for output, ensuring that double spaces are replaced with etc.
|
171 |
-
*
|
172 |
-
* @param array $lines Array of lines to format.
|
173 |
-
* @return array Array of the formatted lines.
|
174 |
-
*/
|
175 |
-
protected function formatLines($lines)
|
176 |
-
{
|
177 |
-
$lines = array_map(array($this, 'ExpandTabs'), $lines);
|
178 |
-
$lines = array_map(array($this, 'HtmlSafe'), $lines);
|
179 |
-
foreach($lines as &$line) {
|
180 |
-
$line = preg_replace_callback('# ( +)|^ #', array($this, 'fixSpaces'), $line);
|
181 |
-
}
|
182 |
-
return $lines;
|
183 |
-
}
|
184 |
-
|
185 |
-
/**
|
186 |
-
* Replace a string containing spaces with a HTML representation using .
|
187 |
-
*
|
188 |
-
* @param string[] $matches Array with preg matches.
|
189 |
-
* @return string The HTML representation of the string.
|
190 |
-
*/
|
191 |
-
private function fixSpaces(array $matches)
|
192 |
-
{
|
193 |
-
$spaces = $matches[1];
|
194 |
-
$count = strlen($spaces);
|
195 |
-
if($count == 0) {
|
196 |
-
return '';
|
197 |
-
}
|
198 |
-
|
199 |
-
$div = floor($count / 2);
|
200 |
-
$mod = $count % 2;
|
201 |
-
return str_repeat(' ', $div).str_repeat(' ', $mod);
|
202 |
-
}
|
203 |
-
|
204 |
-
/**
|
205 |
-
* Replace tabs in a single line with a number of spaces as defined by the tabSize option.
|
206 |
-
*
|
207 |
-
* @param string $line The containing tabs to convert.
|
208 |
-
* @return string The line with the tabs converted to spaces.
|
209 |
-
*/
|
210 |
-
private function expandTabs($line)
|
211 |
-
{
|
212 |
-
return str_replace("\t", str_repeat(' ', $this->options['tabSize']), $line);
|
213 |
-
}
|
214 |
-
|
215 |
-
/**
|
216 |
-
* Make a string containing HTML safe for output on a page.
|
217 |
-
*
|
218 |
-
* @param string $string The string.
|
219 |
-
* @return string The string with the HTML characters replaced by entities.
|
220 |
-
*/
|
221 |
-
private function htmlSafe($string)
|
222 |
-
{
|
223 |
-
return htmlspecialchars($string, ENT_NOQUOTES, 'UTF-8');
|
224 |
-
}
|
225 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Base renderer for rendering HTML based diffs for PHP DiffLib.
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
+
*
|
9 |
+
* All rights reserved.
|
10 |
+
*
|
11 |
+
* Redistribution and use in source and binary forms, with or without
|
12 |
+
* modification, are permitted provided that the following conditions are met:
|
13 |
+
*
|
14 |
+
* - Redistributions of source code must retain the above copyright notice,
|
15 |
+
* this list of conditions and the following disclaimer.
|
16 |
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
+
* this list of conditions and the following disclaimer in the documentation
|
18 |
+
* and/or other materials provided with the distribution.
|
19 |
+
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
+
* may be used to endorse or promote products derived from this software
|
21 |
+
* without specific prior written permission.
|
22 |
+
*
|
23 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
+
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
+
*
|
35 |
+
* @package DiffLib
|
36 |
+
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
+
* @copyright (c) 2009 Chris Boulton
|
38 |
+
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
+
* @version 1.1
|
40 |
+
* @link http://github.com/chrisboulton/php-diff
|
41 |
+
*/
|
42 |
+
|
43 |
+
require_once dirname(__FILE__).'/../Abstract.php';
|
44 |
+
|
45 |
+
class WPR_Diff_Renderer_Html_Array extends WPR_Diff_Renderer_Abstract
|
46 |
+
{
|
47 |
+
/**
|
48 |
+
* @var array Array of the default options that apply to this renderer.
|
49 |
+
*/
|
50 |
+
protected $defaultOptions = array(
|
51 |
+
'tabSize' => 4
|
52 |
+
);
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Render and return an array structure suitable for generating HTML
|
56 |
+
* based differences. Generally called by subclasses that generate a
|
57 |
+
* HTML based diff and return an array of the changes to show in the diff.
|
58 |
+
*
|
59 |
+
* @return array An array of the generated chances, suitable for presentation in HTML.
|
60 |
+
*/
|
61 |
+
public function render()
|
62 |
+
{
|
63 |
+
// As we'll be modifying a & b to include our change markers,
|
64 |
+
// we need to get the contents and store them here. That way
|
65 |
+
// we're not going to destroy the original data
|
66 |
+
$a = $this->diff->getA();
|
67 |
+
$b = $this->diff->getB();
|
68 |
+
|
69 |
+
$changes = array();
|
70 |
+
$opCodes = $this->diff->getGroupedOpcodes();
|
71 |
+
foreach($opCodes as $group) {
|
72 |
+
$blocks = array();
|
73 |
+
$lastTag = null;
|
74 |
+
$lastBlock = 0;
|
75 |
+
foreach($group as $code) {
|
76 |
+
list($tag, $i1, $i2, $j1, $j2) = $code;
|
77 |
+
|
78 |
+
if($tag == 'replace' && $i2 - $i1 == $j2 - $j1) {
|
79 |
+
for($i = 0; $i < ($i2 - $i1); ++$i) {
|
80 |
+
$fromLine = $a[$i1 + $i];
|
81 |
+
$toLine = $b[$j1 + $i];
|
82 |
+
|
83 |
+
list($start, $end) = $this->getChangeExtent($fromLine, $toLine);
|
84 |
+
if($start != 0 || $end != 0) {
|
85 |
+
$last = $end + strlen($fromLine);
|
86 |
+
$fromLine = substr_replace($fromLine, "\0", $start, 0);
|
87 |
+
$fromLine = substr_replace($fromLine, "\1", $last + 1, 0);
|
88 |
+
$last = $end + strlen($toLine);
|
89 |
+
$toLine = substr_replace($toLine, "\0", $start, 0);
|
90 |
+
$toLine = substr_replace($toLine, "\1", $last + 1, 0);
|
91 |
+
$a[$i1 + $i] = $fromLine;
|
92 |
+
$b[$j1 + $i] = $toLine;
|
93 |
+
}
|
94 |
+
}
|
95 |
+
}
|
96 |
+
|
97 |
+
if($tag != $lastTag) {
|
98 |
+
$blocks[] = array(
|
99 |
+
'tag' => $tag,
|
100 |
+
'base' => array(
|
101 |
+
'offset' => $i1,
|
102 |
+
'lines' => array()
|
103 |
+
),
|
104 |
+
'changed' => array(
|
105 |
+
'offset' => $j1,
|
106 |
+
'lines' => array()
|
107 |
+
)
|
108 |
+
);
|
109 |
+
$lastBlock = count($blocks)-1;
|
110 |
+
}
|
111 |
+
|
112 |
+
$lastTag = $tag;
|
113 |
+
|
114 |
+
if($tag == 'equal') {
|
115 |
+
$lines = array_slice($a, $i1, ($i2 - $i1));
|
116 |
+
$blocks[$lastBlock]['base']['lines'] += $this->formatLines($lines);
|
117 |
+
$lines = array_slice($b, $j1, ($j2 - $j1));
|
118 |
+
$blocks[$lastBlock]['changed']['lines'] += $this->formatLines($lines);
|
119 |
+
}
|
120 |
+
else {
|
121 |
+
if($tag == 'replace' || $tag == 'delete') {
|
122 |
+
$lines = array_slice($a, $i1, ($i2 - $i1));
|
123 |
+
$lines = $this->formatLines($lines);
|
124 |
+
$lines = str_replace(array("\0", "\1"), array('<del>', '</del>'), $lines);
|
125 |
+
$blocks[$lastBlock]['base']['lines'] += $lines;
|
126 |
+
}
|
127 |
+
|
128 |
+
if($tag == 'replace' || $tag == 'insert') {
|
129 |
+
$lines = array_slice($b, $j1, ($j2 - $j1));
|
130 |
+
$lines = $this->formatLines($lines);
|
131 |
+
$lines = str_replace(array("\0", "\1"), array('<ins>', '</ins>'), $lines);
|
132 |
+
$blocks[$lastBlock]['changed']['lines'] += $lines;
|
133 |
+
}
|
134 |
+
}
|
135 |
+
}
|
136 |
+
$changes[] = $blocks;
|
137 |
+
}
|
138 |
+
return $changes;
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Given two strings, determine where the changes in the two strings
|
143 |
+
* begin, and where the changes in the two strings end.
|
144 |
+
*
|
145 |
+
* @param string $fromLine The first string.
|
146 |
+
* @param string $toLine The second string.
|
147 |
+
* @return array Array containing the starting position (0 by default) and the ending position (-1 by default)
|
148 |
+
*/
|
149 |
+
private function getChangeExtent($fromLine, $toLine)
|
150 |
+
{
|
151 |
+
$start = 0;
|
152 |
+
$limit = min(strlen($fromLine), strlen($toLine));
|
153 |
+
while($start < $limit && $fromLine{$start} == $toLine{$start}) {
|
154 |
+
++$start;
|
155 |
+
}
|
156 |
+
$end = -1;
|
157 |
+
$limit = $limit - $start;
|
158 |
+
while(-$end <= $limit && substr($fromLine, $end, 1) == substr($toLine, $end, 1)) {
|
159 |
+
--$end;
|
160 |
+
}
|
161 |
+
return array(
|
162 |
+
$start,
|
163 |
+
$end + 1
|
164 |
+
);
|
165 |
+
}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Format a series of lines suitable for output in a HTML rendered diff.
|
169 |
+
* This involves replacing tab characters with spaces, making the HTML safe
|
170 |
+
* for output, ensuring that double spaces are replaced with etc.
|
171 |
+
*
|
172 |
+
* @param array $lines Array of lines to format.
|
173 |
+
* @return array Array of the formatted lines.
|
174 |
+
*/
|
175 |
+
protected function formatLines($lines)
|
176 |
+
{
|
177 |
+
$lines = array_map(array($this, 'ExpandTabs'), $lines);
|
178 |
+
$lines = array_map(array($this, 'HtmlSafe'), $lines);
|
179 |
+
foreach($lines as &$line) {
|
180 |
+
$line = preg_replace_callback('# ( +)|^ #', array($this, 'fixSpaces'), $line);
|
181 |
+
}
|
182 |
+
return $lines;
|
183 |
+
}
|
184 |
+
|
185 |
+
/**
|
186 |
+
* Replace a string containing spaces with a HTML representation using .
|
187 |
+
*
|
188 |
+
* @param string[] $matches Array with preg matches.
|
189 |
+
* @return string The HTML representation of the string.
|
190 |
+
*/
|
191 |
+
private function fixSpaces(array $matches)
|
192 |
+
{
|
193 |
+
$spaces = $matches[1];
|
194 |
+
$count = strlen($spaces);
|
195 |
+
if($count == 0) {
|
196 |
+
return '';
|
197 |
+
}
|
198 |
+
|
199 |
+
$div = floor($count / 2);
|
200 |
+
$mod = $count % 2;
|
201 |
+
return str_repeat(' ', $div).str_repeat(' ', $mod);
|
202 |
+
}
|
203 |
+
|
204 |
+
/**
|
205 |
+
* Replace tabs in a single line with a number of spaces as defined by the tabSize option.
|
206 |
+
*
|
207 |
+
* @param string $line The containing tabs to convert.
|
208 |
+
* @return string The line with the tabs converted to spaces.
|
209 |
+
*/
|
210 |
+
private function expandTabs($line)
|
211 |
+
{
|
212 |
+
return str_replace("\t", str_repeat(' ', $this->options['tabSize']), $line);
|
213 |
+
}
|
214 |
+
|
215 |
+
/**
|
216 |
+
* Make a string containing HTML safe for output on a page.
|
217 |
+
*
|
218 |
+
* @param string $string The string.
|
219 |
+
* @return string The string with the HTML characters replaced by entities.
|
220 |
+
*/
|
221 |
+
private function htmlSafe($string)
|
222 |
+
{
|
223 |
+
return htmlspecialchars($string, ENT_NOQUOTES, 'UTF-8');
|
224 |
+
}
|
225 |
+
}
|
libs/diff/Renderer/Html/Inline.php
CHANGED
@@ -1,143 +1,143 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Inline HTML diff generator for PHP DiffLib.
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
-
*
|
9 |
-
* All rights reserved.
|
10 |
-
*
|
11 |
-
* Redistribution and use in source and binary forms, with or without
|
12 |
-
* modification, are permitted provided that the following conditions are met:
|
13 |
-
*
|
14 |
-
* - Redistributions of source code must retain the above copyright notice,
|
15 |
-
* this list of conditions and the following disclaimer.
|
16 |
-
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
-
* this list of conditions and the following disclaimer in the documentation
|
18 |
-
* and/or other materials provided with the distribution.
|
19 |
-
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
-
* may be used to endorse or promote products derived from this software
|
21 |
-
* without specific prior written permission.
|
22 |
-
*
|
23 |
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
-
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
-
*
|
35 |
-
* @package DiffLib
|
36 |
-
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
-
* @copyright (c) 2009 Chris Boulton
|
38 |
-
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
-
* @version 1.1
|
40 |
-
* @link http://github.com/chrisboulton/php-diff
|
41 |
-
*/
|
42 |
-
|
43 |
-
require_once dirname(__FILE__).'/Array.php';
|
44 |
-
|
45 |
-
class
|
46 |
-
{
|
47 |
-
/**
|
48 |
-
* Render a and return diff with changes between the two sequences
|
49 |
-
* displayed inline (under each other)
|
50 |
-
*
|
51 |
-
* @return string The generated inline diff.
|
52 |
-
*/
|
53 |
-
public function render()
|
54 |
-
{
|
55 |
-
$changes = parent::render();
|
56 |
-
$html = '';
|
57 |
-
if(empty($changes)) {
|
58 |
-
return $html;
|
59 |
-
}
|
60 |
-
|
61 |
-
$html .= '<table class="Differences DifferencesInline">';
|
62 |
-
$html .= '<thead>';
|
63 |
-
$html .= '<tr>';
|
64 |
-
$html .= '<th>Old</th>';
|
65 |
-
$html .= '<th>New</th>';
|
66 |
-
$html .= '<th>Differences</th>';
|
67 |
-
$html .= '</tr>';
|
68 |
-
$html .= '</thead>';
|
69 |
-
foreach($changes as $i => $blocks) {
|
70 |
-
// If this is a separate block, we're condensing code so output ...,
|
71 |
-
// indicating a significant portion of the code has been collapsed as
|
72 |
-
// it is the same
|
73 |
-
if($i > 0) {
|
74 |
-
$html .= '<tbody class="Skipped">';
|
75 |
-
$html .= '<th>…</th>';
|
76 |
-
$html .= '<th>…</th>';
|
77 |
-
$html .= '<td> </td>';
|
78 |
-
$html .= '</tbody>';
|
79 |
-
}
|
80 |
-
|
81 |
-
foreach($blocks as $change) {
|
82 |
-
$html .= '<tbody class="Change'.ucfirst($change['tag']).'">';
|
83 |
-
// Equal changes should be shown on both sides of the diff
|
84 |
-
if($change['tag'] == 'equal') {
|
85 |
-
foreach($change['base']['lines'] as $no => $line) {
|
86 |
-
$fromLine = $change['base']['offset'] + $no + 1;
|
87 |
-
$toLine = $change['changed']['offset'] + $no + 1;
|
88 |
-
$html .= '<tr>';
|
89 |
-
$html .= '<th>'.$fromLine.'</th>';
|
90 |
-
$html .= '<th>'.$toLine.'</th>';
|
91 |
-
$html .= '<td class="Left">'.$line.'</td>';
|
92 |
-
$html .= '</tr>';
|
93 |
-
}
|
94 |
-
}
|
95 |
-
// Added lines only on the right side
|
96 |
-
else if($change['tag'] == 'insert') {
|
97 |
-
foreach($change['changed']['lines'] as $no => $line) {
|
98 |
-
$toLine = $change['changed']['offset'] + $no + 1;
|
99 |
-
$html .= '<tr>';
|
100 |
-
$html .= '<th> </th>';
|
101 |
-
$html .= '<th>'.$toLine.'</th>';
|
102 |
-
$html .= '<td class="Right"><ins>'.$line.'</ins> </td>';
|
103 |
-
$html .= '</tr>';
|
104 |
-
}
|
105 |
-
}
|
106 |
-
// Show deleted lines only on the left side
|
107 |
-
else if($change['tag'] == 'delete') {
|
108 |
-
foreach($change['base']['lines'] as $no => $line) {
|
109 |
-
$fromLine = $change['base']['offset'] + $no + 1;
|
110 |
-
$html .= '<tr>';
|
111 |
-
$html .= '<th>'.$fromLine.'</th>';
|
112 |
-
$html .= '<th> </th>';
|
113 |
-
$html .= '<td class="Left"><del>'.$line.'</del> </td>';
|
114 |
-
$html .= '</tr>';
|
115 |
-
}
|
116 |
-
}
|
117 |
-
// Show modified lines on both sides
|
118 |
-
else if($change['tag'] == 'replace') {
|
119 |
-
foreach($change['base']['lines'] as $no => $line) {
|
120 |
-
$fromLine = $change['base']['offset'] + $no + 1;
|
121 |
-
$html .= '<tr>';
|
122 |
-
$html .= '<th>'.$fromLine.'</th>';
|
123 |
-
$html .= '<th> </th>';
|
124 |
-
$html .= '<td class="Left"><span>'.$line.'</span></td>';
|
125 |
-
$html .= '</tr>';
|
126 |
-
}
|
127 |
-
|
128 |
-
foreach($change['changed']['lines'] as $no => $line) {
|
129 |
-
$toLine = $change['changed']['offset'] + $no + 1;
|
130 |
-
$html .= '<tr>';
|
131 |
-
$html .= '<th> </th>';
|
132 |
-
$html .= '<th>'.$toLine.'</th>';
|
133 |
-
$html .= '<td class="Right"><span>'.$line.'</span></td>';
|
134 |
-
$html .= '</tr>';
|
135 |
-
}
|
136 |
-
}
|
137 |
-
$html .= '</tbody>';
|
138 |
-
}
|
139 |
-
}
|
140 |
-
$html .= '</table>';
|
141 |
-
return $html;
|
142 |
-
}
|
143 |
-
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Inline HTML diff generator for PHP DiffLib.
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
+
*
|
9 |
+
* All rights reserved.
|
10 |
+
*
|
11 |
+
* Redistribution and use in source and binary forms, with or without
|
12 |
+
* modification, are permitted provided that the following conditions are met:
|
13 |
+
*
|
14 |
+
* - Redistributions of source code must retain the above copyright notice,
|
15 |
+
* this list of conditions and the following disclaimer.
|
16 |
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
+
* this list of conditions and the following disclaimer in the documentation
|
18 |
+
* and/or other materials provided with the distribution.
|
19 |
+
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
+
* may be used to endorse or promote products derived from this software
|
21 |
+
* without specific prior written permission.
|
22 |
+
*
|
23 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
+
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
+
*
|
35 |
+
* @package DiffLib
|
36 |
+
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
+
* @copyright (c) 2009 Chris Boulton
|
38 |
+
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
+
* @version 1.1
|
40 |
+
* @link http://github.com/chrisboulton/php-diff
|
41 |
+
*/
|
42 |
+
|
43 |
+
require_once dirname(__FILE__).'/Array.php';
|
44 |
+
|
45 |
+
class WPR_Diff_Renderer_Html_Inline extends WPR_Diff_Renderer_Html_Array
|
46 |
+
{
|
47 |
+
/**
|
48 |
+
* Render a and return diff with changes between the two sequences
|
49 |
+
* displayed inline (under each other)
|
50 |
+
*
|
51 |
+
* @return string The generated inline diff.
|
52 |
+
*/
|
53 |
+
public function render()
|
54 |
+
{
|
55 |
+
$changes = parent::render();
|
56 |
+
$html = '';
|
57 |
+
if(empty($changes)) {
|
58 |
+
return $html;
|
59 |
+
}
|
60 |
+
|
61 |
+
$html .= '<table class="Differences DifferencesInline">';
|
62 |
+
$html .= '<thead>';
|
63 |
+
$html .= '<tr>';
|
64 |
+
$html .= '<th>Old</th>';
|
65 |
+
$html .= '<th>New</th>';
|
66 |
+
$html .= '<th>Differences</th>';
|
67 |
+
$html .= '</tr>';
|
68 |
+
$html .= '</thead>';
|
69 |
+
foreach($changes as $i => $blocks) {
|
70 |
+
// If this is a separate block, we're condensing code so output ...,
|
71 |
+
// indicating a significant portion of the code has been collapsed as
|
72 |
+
// it is the same
|
73 |
+
if($i > 0) {
|
74 |
+
$html .= '<tbody class="Skipped">';
|
75 |
+
$html .= '<th>…</th>';
|
76 |
+
$html .= '<th>…</th>';
|
77 |
+
$html .= '<td> </td>';
|
78 |
+
$html .= '</tbody>';
|
79 |
+
}
|
80 |
+
|
81 |
+
foreach($blocks as $change) {
|
82 |
+
$html .= '<tbody class="Change'.ucfirst($change['tag']).'">';
|
83 |
+
// Equal changes should be shown on both sides of the diff
|
84 |
+
if($change['tag'] == 'equal') {
|
85 |
+
foreach($change['base']['lines'] as $no => $line) {
|
86 |
+
$fromLine = $change['base']['offset'] + $no + 1;
|
87 |
+
$toLine = $change['changed']['offset'] + $no + 1;
|
88 |
+
$html .= '<tr>';
|
89 |
+
$html .= '<th>'.$fromLine.'</th>';
|
90 |
+
$html .= '<th>'.$toLine.'</th>';
|
91 |
+
$html .= '<td class="Left">'.$line.'</td>';
|
92 |
+
$html .= '</tr>';
|
93 |
+
}
|
94 |
+
}
|
95 |
+
// Added lines only on the right side
|
96 |
+
else if($change['tag'] == 'insert') {
|
97 |
+
foreach($change['changed']['lines'] as $no => $line) {
|
98 |
+
$toLine = $change['changed']['offset'] + $no + 1;
|
99 |
+
$html .= '<tr>';
|
100 |
+
$html .= '<th> </th>';
|
101 |
+
$html .= '<th>'.$toLine.'</th>';
|
102 |
+
$html .= '<td class="Right"><ins>'.$line.'</ins> </td>';
|
103 |
+
$html .= '</tr>';
|
104 |
+
}
|
105 |
+
}
|
106 |
+
// Show deleted lines only on the left side
|
107 |
+
else if($change['tag'] == 'delete') {
|
108 |
+
foreach($change['base']['lines'] as $no => $line) {
|
109 |
+
$fromLine = $change['base']['offset'] + $no + 1;
|
110 |
+
$html .= '<tr>';
|
111 |
+
$html .= '<th>'.$fromLine.'</th>';
|
112 |
+
$html .= '<th> </th>';
|
113 |
+
$html .= '<td class="Left"><del>'.$line.'</del> </td>';
|
114 |
+
$html .= '</tr>';
|
115 |
+
}
|
116 |
+
}
|
117 |
+
// Show modified lines on both sides
|
118 |
+
else if($change['tag'] == 'replace') {
|
119 |
+
foreach($change['base']['lines'] as $no => $line) {
|
120 |
+
$fromLine = $change['base']['offset'] + $no + 1;
|
121 |
+
$html .= '<tr>';
|
122 |
+
$html .= '<th>'.$fromLine.'</th>';
|
123 |
+
$html .= '<th> </th>';
|
124 |
+
$html .= '<td class="Left"><span>'.$line.'</span></td>';
|
125 |
+
$html .= '</tr>';
|
126 |
+
}
|
127 |
+
|
128 |
+
foreach($change['changed']['lines'] as $no => $line) {
|
129 |
+
$toLine = $change['changed']['offset'] + $no + 1;
|
130 |
+
$html .= '<tr>';
|
131 |
+
$html .= '<th> </th>';
|
132 |
+
$html .= '<th>'.$toLine.'</th>';
|
133 |
+
$html .= '<td class="Right"><span>'.$line.'</span></td>';
|
134 |
+
$html .= '</tr>';
|
135 |
+
}
|
136 |
+
}
|
137 |
+
$html .= '</tbody>';
|
138 |
+
}
|
139 |
+
}
|
140 |
+
$html .= '</table>';
|
141 |
+
return $html;
|
142 |
+
}
|
143 |
+
}
|
libs/diff/Renderer/Html/SideBySide.php
CHANGED
@@ -1,163 +1,163 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Side by Side HTML diff generator for PHP DiffLib.
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
-
*
|
9 |
-
* All rights reserved.
|
10 |
-
*
|
11 |
-
* Redistribution and use in source and binary forms, with or without
|
12 |
-
* modification, are permitted provided that the following conditions are met:
|
13 |
-
*
|
14 |
-
* - Redistributions of source code must retain the above copyright notice,
|
15 |
-
* this list of conditions and the following disclaimer.
|
16 |
-
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
-
* this list of conditions and the following disclaimer in the documentation
|
18 |
-
* and/or other materials provided with the distribution.
|
19 |
-
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
-
* may be used to endorse or promote products derived from this software
|
21 |
-
* without specific prior written permission.
|
22 |
-
*
|
23 |
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
-
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
-
*
|
35 |
-
* @package DiffLib
|
36 |
-
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
-
* @copyright (c) 2009 Chris Boulton
|
38 |
-
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
-
* @version 1.1
|
40 |
-
* @link http://github.com/chrisboulton/php-diff
|
41 |
-
*/
|
42 |
-
|
43 |
-
require_once dirname(__FILE__).'/Array.php';
|
44 |
-
|
45 |
-
class
|
46 |
-
{
|
47 |
-
/**
|
48 |
-
* Render a and return diff with changes between the two sequences
|
49 |
-
* displayed side by side.
|
50 |
-
*
|
51 |
-
* @return string The generated side by side diff.
|
52 |
-
*/
|
53 |
-
public function render()
|
54 |
-
{
|
55 |
-
$changes = parent::render();
|
56 |
-
|
57 |
-
$html = '';
|
58 |
-
if(empty($changes)) {
|
59 |
-
return $html;
|
60 |
-
}
|
61 |
-
|
62 |
-
$html .= '<table class="Differences DifferencesSideBySide">';
|
63 |
-
//$html .= '<thead>';
|
64 |
-
//$html .= '<tr>';
|
65 |
-
//$html .= '<th colspan="2">Old Version</th>';
|
66 |
-
//$html .= '<th colspan="2">New Version</th>';
|
67 |
-
//$html .= '</tr>';
|
68 |
-
//$html .= '</thead>';
|
69 |
-
foreach($changes as $i => $blocks) {
|
70 |
-
if($i > 0) {
|
71 |
-
$html .= '<tbody class="Skipped">';
|
72 |
-
$html .= '<th>…</th><td> </td>';
|
73 |
-
$html .= '<th>…</th><td> </td>';
|
74 |
-
$html .= '</tbody>';
|
75 |
-
}
|
76 |
-
|
77 |
-
foreach($blocks as $change) {
|
78 |
-
$html .= '<tbody class="Change'.ucfirst($change['tag']).'">';
|
79 |
-
// Equal changes should be shown on both sides of the diff
|
80 |
-
if($change['tag'] == 'equal') {
|
81 |
-
foreach($change['base']['lines'] as $no => $line) {
|
82 |
-
$fromLine = $change['base']['offset'] + $no + 1;
|
83 |
-
$toLine = $change['changed']['offset'] + $no + 1;
|
84 |
-
$html .= '<tr>';
|
85 |
-
$html .= '<th>'.$fromLine.'</th>';
|
86 |
-
$html .= '<td class="Left"><span>'.$line.'</span> </span></td>';
|
87 |
-
$html .= '<th>'.$toLine.'</th>';
|
88 |
-
$html .= '<td class="Right"><span>'.$line.'</span> </span></td>';
|
89 |
-
$html .= '</tr>';
|
90 |
-
}
|
91 |
-
}
|
92 |
-
// Added lines only on the right side
|
93 |
-
else if($change['tag'] == 'insert') {
|
94 |
-
foreach($change['changed']['lines'] as $no => $line) {
|
95 |
-
$toLine = $change['changed']['offset'] + $no + 1;
|
96 |
-
$html .= '<tr>';
|
97 |
-
$html .= '<th> </th>';
|
98 |
-
$html .= '<td class="Left"> </td>';
|
99 |
-
$html .= '<th>'.$toLine.'</th>';
|
100 |
-
$html .= '<td class="Right"><ins>'.$line.'</ins> </td>';
|
101 |
-
$html .= '</tr>';
|
102 |
-
}
|
103 |
-
}
|
104 |
-
// Show deleted lines only on the left side
|
105 |
-
else if($change['tag'] == 'delete') {
|
106 |
-
foreach($change['base']['lines'] as $no => $line) {
|
107 |
-
$fromLine = $change['base']['offset'] + $no + 1;
|
108 |
-
$html .= '<tr>';
|
109 |
-
$html .= '<th>'.$fromLine.'</th>';
|
110 |
-
$html .= '<td class="Left"><del>'.$line.'</del> </td>';
|
111 |
-
$html .= '<th> </th>';
|
112 |
-
$html .= '<td class="Right"> </td>';
|
113 |
-
$html .= '</tr>';
|
114 |
-
}
|
115 |
-
}
|
116 |
-
// Show modified lines on both sides
|
117 |
-
else if($change['tag'] == 'replace') {
|
118 |
-
if(count($change['base']['lines']) >= count($change['changed']['lines'])) {
|
119 |
-
foreach($change['base']['lines'] as $no => $line) {
|
120 |
-
$fromLine = $change['base']['offset'] + $no + 1;
|
121 |
-
$html .= '<tr>';
|
122 |
-
$html .= '<th>'.$fromLine.'</th>';
|
123 |
-
$html .= '<td class="Left"><span>'.$line.'</span> </td>';
|
124 |
-
if(!isset($change['changed']['lines'][$no])) {
|
125 |
-
$toLine = ' ';
|
126 |
-
$changedLine = ' ';
|
127 |
-
}
|
128 |
-
else {
|
129 |
-
$toLine = $change['base']['offset'] + $no + 1;
|
130 |
-
$changedLine = '<span>'.$change['changed']['lines'][$no].'</span>';
|
131 |
-
}
|
132 |
-
$html .= '<th>'.$toLine.'</th>';
|
133 |
-
$html .= '<td class="Right">'.$changedLine.'</td>';
|
134 |
-
$html .= '</tr>';
|
135 |
-
}
|
136 |
-
}
|
137 |
-
else {
|
138 |
-
foreach($change['changed']['lines'] as $no => $changedLine) {
|
139 |
-
if(!isset($change['base']['lines'][$no])) {
|
140 |
-
$fromLine = ' ';
|
141 |
-
$line = ' ';
|
142 |
-
}
|
143 |
-
else {
|
144 |
-
$fromLine = $change['base']['offset'] + $no + 1;
|
145 |
-
$line = '<span>'.$change['base']['lines'][$no].'</span>';
|
146 |
-
}
|
147 |
-
$html .= '<tr>';
|
148 |
-
$html .= '<th>'.$fromLine.'</th>';
|
149 |
-
$html .= '<td class="Left"><span>'.$line.'</span> </td>';
|
150 |
-
$toLine = $change['changed']['offset'] + $no + 1;
|
151 |
-
$html .= '<th>'.$toLine.'</th>';
|
152 |
-
$html .= '<td class="Right">'.$changedLine.'</td>';
|
153 |
-
$html .= '</tr>';
|
154 |
-
}
|
155 |
-
}
|
156 |
-
}
|
157 |
-
$html .= '</tbody>';
|
158 |
-
}
|
159 |
-
}
|
160 |
-
$html .= '</table>';
|
161 |
-
return $html;
|
162 |
-
}
|
163 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Side by Side HTML diff generator for PHP DiffLib.
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
+
*
|
9 |
+
* All rights reserved.
|
10 |
+
*
|
11 |
+
* Redistribution and use in source and binary forms, with or without
|
12 |
+
* modification, are permitted provided that the following conditions are met:
|
13 |
+
*
|
14 |
+
* - Redistributions of source code must retain the above copyright notice,
|
15 |
+
* this list of conditions and the following disclaimer.
|
16 |
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
+
* this list of conditions and the following disclaimer in the documentation
|
18 |
+
* and/or other materials provided with the distribution.
|
19 |
+
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
+
* may be used to endorse or promote products derived from this software
|
21 |
+
* without specific prior written permission.
|
22 |
+
*
|
23 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
+
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
+
*
|
35 |
+
* @package DiffLib
|
36 |
+
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
+
* @copyright (c) 2009 Chris Boulton
|
38 |
+
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
+
* @version 1.1
|
40 |
+
* @link http://github.com/chrisboulton/php-diff
|
41 |
+
*/
|
42 |
+
|
43 |
+
require_once dirname(__FILE__).'/Array.php';
|
44 |
+
|
45 |
+
class WPR_Diff_Renderer_Html_SideBySide extends WPR_Diff_Renderer_Html_Array
|
46 |
+
{
|
47 |
+
/**
|
48 |
+
* Render a and return diff with changes between the two sequences
|
49 |
+
* displayed side by side.
|
50 |
+
*
|
51 |
+
* @return string The generated side by side diff.
|
52 |
+
*/
|
53 |
+
public function render()
|
54 |
+
{
|
55 |
+
$changes = parent::render();
|
56 |
+
|
57 |
+
$html = '';
|
58 |
+
if(empty($changes)) {
|
59 |
+
return $html;
|
60 |
+
}
|
61 |
+
|
62 |
+
$html .= '<table class="Differences DifferencesSideBySide">';
|
63 |
+
//$html .= '<thead>';
|
64 |
+
//$html .= '<tr>';
|
65 |
+
//$html .= '<th colspan="2">Old Version</th>';
|
66 |
+
//$html .= '<th colspan="2">New Version</th>';
|
67 |
+
//$html .= '</tr>';
|
68 |
+
//$html .= '</thead>';
|
69 |
+
foreach($changes as $i => $blocks) {
|
70 |
+
if($i > 0) {
|
71 |
+
$html .= '<tbody class="Skipped">';
|
72 |
+
$html .= '<th>…</th><td> </td>';
|
73 |
+
$html .= '<th>…</th><td> </td>';
|
74 |
+
$html .= '</tbody>';
|
75 |
+
}
|
76 |
+
|
77 |
+
foreach($blocks as $change) {
|
78 |
+
$html .= '<tbody class="Change'.ucfirst($change['tag']).'">';
|
79 |
+
// Equal changes should be shown on both sides of the diff
|
80 |
+
if($change['tag'] == 'equal') {
|
81 |
+
foreach($change['base']['lines'] as $no => $line) {
|
82 |
+
$fromLine = $change['base']['offset'] + $no + 1;
|
83 |
+
$toLine = $change['changed']['offset'] + $no + 1;
|
84 |
+
$html .= '<tr>';
|
85 |
+
$html .= '<th>'.$fromLine.'</th>';
|
86 |
+
$html .= '<td class="Left"><span>'.$line.'</span> </span></td>';
|
87 |
+
$html .= '<th>'.$toLine.'</th>';
|
88 |
+
$html .= '<td class="Right"><span>'.$line.'</span> </span></td>';
|
89 |
+
$html .= '</tr>';
|
90 |
+
}
|
91 |
+
}
|
92 |
+
// Added lines only on the right side
|
93 |
+
else if($change['tag'] == 'insert') {
|
94 |
+
foreach($change['changed']['lines'] as $no => $line) {
|
95 |
+
$toLine = $change['changed']['offset'] + $no + 1;
|
96 |
+
$html .= '<tr>';
|
97 |
+
$html .= '<th> </th>';
|
98 |
+
$html .= '<td class="Left"> </td>';
|
99 |
+
$html .= '<th>'.$toLine.'</th>';
|
100 |
+
$html .= '<td class="Right"><ins>'.$line.'</ins> </td>';
|
101 |
+
$html .= '</tr>';
|
102 |
+
}
|
103 |
+
}
|
104 |
+
// Show deleted lines only on the left side
|
105 |
+
else if($change['tag'] == 'delete') {
|
106 |
+
foreach($change['base']['lines'] as $no => $line) {
|
107 |
+
$fromLine = $change['base']['offset'] + $no + 1;
|
108 |
+
$html .= '<tr>';
|
109 |
+
$html .= '<th>'.$fromLine.'</th>';
|
110 |
+
$html .= '<td class="Left"><del>'.$line.'</del> </td>';
|
111 |
+
$html .= '<th> </th>';
|
112 |
+
$html .= '<td class="Right"> </td>';
|
113 |
+
$html .= '</tr>';
|
114 |
+
}
|
115 |
+
}
|
116 |
+
// Show modified lines on both sides
|
117 |
+
else if($change['tag'] == 'replace') {
|
118 |
+
if(count($change['base']['lines']) >= count($change['changed']['lines'])) {
|
119 |
+
foreach($change['base']['lines'] as $no => $line) {
|
120 |
+
$fromLine = $change['base']['offset'] + $no + 1;
|
121 |
+
$html .= '<tr>';
|
122 |
+
$html .= '<th>'.$fromLine.'</th>';
|
123 |
+
$html .= '<td class="Left"><span>'.$line.'</span> </td>';
|
124 |
+
if(!isset($change['changed']['lines'][$no])) {
|
125 |
+
$toLine = ' ';
|
126 |
+
$changedLine = ' ';
|
127 |
+
}
|
128 |
+
else {
|
129 |
+
$toLine = $change['base']['offset'] + $no + 1;
|
130 |
+
$changedLine = '<span>'.$change['changed']['lines'][$no].'</span>';
|
131 |
+
}
|
132 |
+
$html .= '<th>'.$toLine.'</th>';
|
133 |
+
$html .= '<td class="Right">'.$changedLine.'</td>';
|
134 |
+
$html .= '</tr>';
|
135 |
+
}
|
136 |
+
}
|
137 |
+
else {
|
138 |
+
foreach($change['changed']['lines'] as $no => $changedLine) {
|
139 |
+
if(!isset($change['base']['lines'][$no])) {
|
140 |
+
$fromLine = ' ';
|
141 |
+
$line = ' ';
|
142 |
+
}
|
143 |
+
else {
|
144 |
+
$fromLine = $change['base']['offset'] + $no + 1;
|
145 |
+
$line = '<span>'.$change['base']['lines'][$no].'</span>';
|
146 |
+
}
|
147 |
+
$html .= '<tr>';
|
148 |
+
$html .= '<th>'.$fromLine.'</th>';
|
149 |
+
$html .= '<td class="Left"><span>'.$line.'</span> </td>';
|
150 |
+
$toLine = $change['changed']['offset'] + $no + 1;
|
151 |
+
$html .= '<th>'.$toLine.'</th>';
|
152 |
+
$html .= '<td class="Right">'.$changedLine.'</td>';
|
153 |
+
$html .= '</tr>';
|
154 |
+
}
|
155 |
+
}
|
156 |
+
}
|
157 |
+
$html .= '</tbody>';
|
158 |
+
}
|
159 |
+
}
|
160 |
+
$html .= '</table>';
|
161 |
+
return $html;
|
162 |
+
}
|
163 |
}
|
libs/diff/Renderer/Text/Context.php
CHANGED
@@ -1,128 +1,128 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Context diff generator for PHP DiffLib.
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
-
*
|
9 |
-
* All rights reserved.
|
10 |
-
*
|
11 |
-
* Redistribution and use in source and binary forms, with or without
|
12 |
-
* modification, are permitted provided that the following conditions are met:
|
13 |
-
*
|
14 |
-
* - Redistributions of source code must retain the above copyright notice,
|
15 |
-
* this list of conditions and the following disclaimer.
|
16 |
-
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
-
* this list of conditions and the following disclaimer in the documentation
|
18 |
-
* and/or other materials provided with the distribution.
|
19 |
-
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
-
* may be used to endorse or promote products derived from this software
|
21 |
-
* without specific prior written permission.
|
22 |
-
*
|
23 |
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
-
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
-
*
|
35 |
-
* @package DiffLib
|
36 |
-
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
-
* @copyright (c) 2009 Chris Boulton
|
38 |
-
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
-
* @version 1.1
|
40 |
-
* @link http://github.com/chrisboulton/php-diff
|
41 |
-
*/
|
42 |
-
|
43 |
-
require_once dirname(__FILE__).'/../Abstract.php';
|
44 |
-
|
45 |
-
class
|
46 |
-
{
|
47 |
-
/**
|
48 |
-
* @var array Array of the different opcode tags and how they map to the context diff equivalent.
|
49 |
-
*/
|
50 |
-
private $tagMap = array(
|
51 |
-
'insert' => '+',
|
52 |
-
'delete' => '-',
|
53 |
-
'replace' => '!',
|
54 |
-
'equal' => ' '
|
55 |
-
);
|
56 |
-
|
57 |
-
/**
|
58 |
-
* Render and return a context formatted (old school!) diff file.
|
59 |
-
*
|
60 |
-
* @return string The generated context diff.
|
61 |
-
*/
|
62 |
-
public function render()
|
63 |
-
{
|
64 |
-
$diff = '';
|
65 |
-
$opCodes = $this->diff->getGroupedOpcodes();
|
66 |
-
foreach($opCodes as $group) {
|
67 |
-
$diff .= "***************\n";
|
68 |
-
$lastItem = count($group)-1;
|
69 |
-
$i1 = $group[0][1];
|
70 |
-
$i2 = $group[$lastItem][2];
|
71 |
-
$j1 = $group[0][3];
|
72 |
-
$j2 = $group[$lastItem][4];
|
73 |
-
|
74 |
-
if($i2 - $i1 >= 2) {
|
75 |
-
$diff .= '*** '.($group[0][1] + 1).','.$i2." ****\n";
|
76 |
-
}
|
77 |
-
else {
|
78 |
-
$diff .= '*** '.$i2." ****\n";
|
79 |
-
}
|
80 |
-
|
81 |
-
if($j2 - $j1 >= 2) {
|
82 |
-
$separator = '--- '.($j1 + 1).','.$j2." ----\n";
|
83 |
-
}
|
84 |
-
else {
|
85 |
-
$separator = '--- '.$j2." ----\n";
|
86 |
-
}
|
87 |
-
|
88 |
-
$hasVisible = false;
|
89 |
-
foreach($group as $code) {
|
90 |
-
if($code[0] == 'replace' || $code[0] == 'delete') {
|
91 |
-
$hasVisible = true;
|
92 |
-
break;
|
93 |
-
}
|
94 |
-
}
|
95 |
-
|
96 |
-
if($hasVisible) {
|
97 |
-
foreach($group as $code) {
|
98 |
-
list($tag, $i1, $i2, $j1, $j2) = $code;
|
99 |
-
if($tag == 'insert') {
|
100 |
-
continue;
|
101 |
-
}
|
102 |
-
$diff .= $this->tagMap[$tag].' '.implode("\n".$this->tagMap[$tag].' ', $this->diff->GetA($i1, $i2))."\n";
|
103 |
-
}
|
104 |
-
}
|
105 |
-
|
106 |
-
$hasVisible = false;
|
107 |
-
foreach($group as $code) {
|
108 |
-
if($code[0] == 'replace' || $code[0] == 'insert') {
|
109 |
-
$hasVisible = true;
|
110 |
-
break;
|
111 |
-
}
|
112 |
-
}
|
113 |
-
|
114 |
-
$diff .= $separator;
|
115 |
-
|
116 |
-
if($hasVisible) {
|
117 |
-
foreach($group as $code) {
|
118 |
-
list($tag, $i1, $i2, $j1, $j2) = $code;
|
119 |
-
if($tag == 'delete') {
|
120 |
-
continue;
|
121 |
-
}
|
122 |
-
$diff .= $this->tagMap[$tag].' '.implode("\n".$this->tagMap[$tag].' ', $this->diff->GetB($j1, $j2))."\n";
|
123 |
-
}
|
124 |
-
}
|
125 |
-
}
|
126 |
-
return $diff;
|
127 |
-
}
|
128 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Context diff generator for PHP DiffLib.
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
+
*
|
9 |
+
* All rights reserved.
|
10 |
+
*
|
11 |
+
* Redistribution and use in source and binary forms, with or without
|
12 |
+
* modification, are permitted provided that the following conditions are met:
|
13 |
+
*
|
14 |
+
* - Redistributions of source code must retain the above copyright notice,
|
15 |
+
* this list of conditions and the following disclaimer.
|
16 |
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
+
* this list of conditions and the following disclaimer in the documentation
|
18 |
+
* and/or other materials provided with the distribution.
|
19 |
+
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
+
* may be used to endorse or promote products derived from this software
|
21 |
+
* without specific prior written permission.
|
22 |
+
*
|
23 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
+
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
+
*
|
35 |
+
* @package DiffLib
|
36 |
+
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
+
* @copyright (c) 2009 Chris Boulton
|
38 |
+
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
+
* @version 1.1
|
40 |
+
* @link http://github.com/chrisboulton/php-diff
|
41 |
+
*/
|
42 |
+
|
43 |
+
require_once dirname(__FILE__).'/../Abstract.php';
|
44 |
+
|
45 |
+
class WPR_Diff_Renderer_Text_Context extends WPR_Diff_Renderer_Abstract
|
46 |
+
{
|
47 |
+
/**
|
48 |
+
* @var array Array of the different opcode tags and how they map to the context diff equivalent.
|
49 |
+
*/
|
50 |
+
private $tagMap = array(
|
51 |
+
'insert' => '+',
|
52 |
+
'delete' => '-',
|
53 |
+
'replace' => '!',
|
54 |
+
'equal' => ' '
|
55 |
+
);
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Render and return a context formatted (old school!) diff file.
|
59 |
+
*
|
60 |
+
* @return string The generated context diff.
|
61 |
+
*/
|
62 |
+
public function render()
|
63 |
+
{
|
64 |
+
$diff = '';
|
65 |
+
$opCodes = $this->diff->getGroupedOpcodes();
|
66 |
+
foreach($opCodes as $group) {
|
67 |
+
$diff .= "***************\n";
|
68 |
+
$lastItem = count($group)-1;
|
69 |
+
$i1 = $group[0][1];
|
70 |
+
$i2 = $group[$lastItem][2];
|
71 |
+
$j1 = $group[0][3];
|
72 |
+
$j2 = $group[$lastItem][4];
|
73 |
+
|
74 |
+
if($i2 - $i1 >= 2) {
|
75 |
+
$diff .= '*** '.($group[0][1] + 1).','.$i2." ****\n";
|
76 |
+
}
|
77 |
+
else {
|
78 |
+
$diff .= '*** '.$i2." ****\n";
|
79 |
+
}
|
80 |
+
|
81 |
+
if($j2 - $j1 >= 2) {
|
82 |
+
$separator = '--- '.($j1 + 1).','.$j2." ----\n";
|
83 |
+
}
|
84 |
+
else {
|
85 |
+
$separator = '--- '.$j2." ----\n";
|
86 |
+
}
|
87 |
+
|
88 |
+
$hasVisible = false;
|
89 |
+
foreach($group as $code) {
|
90 |
+
if($code[0] == 'replace' || $code[0] == 'delete') {
|
91 |
+
$hasVisible = true;
|
92 |
+
break;
|
93 |
+
}
|
94 |
+
}
|
95 |
+
|
96 |
+
if($hasVisible) {
|
97 |
+
foreach($group as $code) {
|
98 |
+
list($tag, $i1, $i2, $j1, $j2) = $code;
|
99 |
+
if($tag == 'insert') {
|
100 |
+
continue;
|
101 |
+
}
|
102 |
+
$diff .= $this->tagMap[$tag].' '.implode("\n".$this->tagMap[$tag].' ', $this->diff->GetA($i1, $i2))."\n";
|
103 |
+
}
|
104 |
+
}
|
105 |
+
|
106 |
+
$hasVisible = false;
|
107 |
+
foreach($group as $code) {
|
108 |
+
if($code[0] == 'replace' || $code[0] == 'insert') {
|
109 |
+
$hasVisible = true;
|
110 |
+
break;
|
111 |
+
}
|
112 |
+
}
|
113 |
+
|
114 |
+
$diff .= $separator;
|
115 |
+
|
116 |
+
if($hasVisible) {
|
117 |
+
foreach($group as $code) {
|
118 |
+
list($tag, $i1, $i2, $j1, $j2) = $code;
|
119 |
+
if($tag == 'delete') {
|
120 |
+
continue;
|
121 |
+
}
|
122 |
+
$diff .= $this->tagMap[$tag].' '.implode("\n".$this->tagMap[$tag].' ', $this->diff->GetB($j1, $j2))."\n";
|
123 |
+
}
|
124 |
+
}
|
125 |
+
}
|
126 |
+
return $diff;
|
127 |
+
}
|
128 |
}
|
libs/diff/Renderer/Text/Unified.php
CHANGED
@@ -1,87 +1,87 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Unified diff generator for PHP DiffLib.
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
-
*
|
9 |
-
* All rights reserved.
|
10 |
-
*
|
11 |
-
* Redistribution and use in source and binary forms, with or without
|
12 |
-
* modification, are permitted provided that the following conditions are met:
|
13 |
-
*
|
14 |
-
* - Redistributions of source code must retain the above copyright notice,
|
15 |
-
* this list of conditions and the following disclaimer.
|
16 |
-
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
-
* this list of conditions and the following disclaimer in the documentation
|
18 |
-
* and/or other materials provided with the distribution.
|
19 |
-
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
-
* may be used to endorse or promote products derived from this software
|
21 |
-
* without specific prior written permission.
|
22 |
-
*
|
23 |
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
-
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
-
*
|
35 |
-
* @package DiffLib
|
36 |
-
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
-
* @copyright (c) 2009 Chris Boulton
|
38 |
-
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
-
* @version 1.1
|
40 |
-
* @link http://github.com/chrisboulton/php-diff
|
41 |
-
*/
|
42 |
-
|
43 |
-
require_once dirname(__FILE__).'/../Abstract.php';
|
44 |
-
|
45 |
-
class
|
46 |
-
{
|
47 |
-
/**
|
48 |
-
* Render and return a unified diff.
|
49 |
-
*
|
50 |
-
* @return string The unified diff.
|
51 |
-
*/
|
52 |
-
public function render()
|
53 |
-
{
|
54 |
-
$diff = '';
|
55 |
-
$opCodes = $this->diff->getGroupedOpcodes();
|
56 |
-
foreach($opCodes as $group) {
|
57 |
-
$lastItem = count($group)-1;
|
58 |
-
$i1 = $group[0][1];
|
59 |
-
$i2 = $group[$lastItem][2];
|
60 |
-
$j1 = $group[0][3];
|
61 |
-
$j2 = $group[$lastItem][4];
|
62 |
-
|
63 |
-
if($i1 == 0 && $i2 == 0) {
|
64 |
-
$i1 = -1;
|
65 |
-
$i2 = -1;
|
66 |
-
}
|
67 |
-
|
68 |
-
$diff .= '@@ -'.($i1 + 1).','.($i2 - $i1).' +'.($j1 + 1).','.($j2 - $j1)." @@\n";
|
69 |
-
foreach($group as $code) {
|
70 |
-
list($tag, $i1, $i2, $j1, $j2) = $code;
|
71 |
-
if($tag == 'equal') {
|
72 |
-
$diff .= ' '.implode("\n ", $this->diff->GetA($i1, $i2))."\n";
|
73 |
-
}
|
74 |
-
else {
|
75 |
-
if($tag == 'replace' || $tag == 'delete') {
|
76 |
-
$diff .= '-'.implode("\n-", $this->diff->GetA($i1, $i2))."\n";
|
77 |
-
}
|
78 |
-
|
79 |
-
if($tag == 'replace' || $tag == 'insert') {
|
80 |
-
$diff .= '+'.implode("\n+", $this->diff->GetB($j1, $j2))."\n";
|
81 |
-
}
|
82 |
-
}
|
83 |
-
}
|
84 |
-
}
|
85 |
-
return $diff;
|
86 |
-
}
|
87 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Unified diff generator for PHP DiffLib.
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
+
*
|
9 |
+
* All rights reserved.
|
10 |
+
*
|
11 |
+
* Redistribution and use in source and binary forms, with or without
|
12 |
+
* modification, are permitted provided that the following conditions are met:
|
13 |
+
*
|
14 |
+
* - Redistributions of source code must retain the above copyright notice,
|
15 |
+
* this list of conditions and the following disclaimer.
|
16 |
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
+
* this list of conditions and the following disclaimer in the documentation
|
18 |
+
* and/or other materials provided with the distribution.
|
19 |
+
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
+
* may be used to endorse or promote products derived from this software
|
21 |
+
* without specific prior written permission.
|
22 |
+
*
|
23 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
+
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
+
*
|
35 |
+
* @package DiffLib
|
36 |
+
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
+
* @copyright (c) 2009 Chris Boulton
|
38 |
+
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
+
* @version 1.1
|
40 |
+
* @link http://github.com/chrisboulton/php-diff
|
41 |
+
*/
|
42 |
+
|
43 |
+
require_once dirname(__FILE__).'/../Abstract.php';
|
44 |
+
|
45 |
+
class WPR_Diff_Renderer_Text_Unified extends WPR_Diff_Renderer_Abstract
|
46 |
+
{
|
47 |
+
/**
|
48 |
+
* Render and return a unified diff.
|
49 |
+
*
|
50 |
+
* @return string The unified diff.
|
51 |
+
*/
|
52 |
+
public function render()
|
53 |
+
{
|
54 |
+
$diff = '';
|
55 |
+
$opCodes = $this->diff->getGroupedOpcodes();
|
56 |
+
foreach($opCodes as $group) {
|
57 |
+
$lastItem = count($group)-1;
|
58 |
+
$i1 = $group[0][1];
|
59 |
+
$i2 = $group[$lastItem][2];
|
60 |
+
$j1 = $group[0][3];
|
61 |
+
$j2 = $group[$lastItem][4];
|
62 |
+
|
63 |
+
if($i1 == 0 && $i2 == 0) {
|
64 |
+
$i1 = -1;
|
65 |
+
$i2 = -1;
|
66 |
+
}
|
67 |
+
|
68 |
+
$diff .= '@@ -'.($i1 + 1).','.($i2 - $i1).' +'.($j1 + 1).','.($j2 - $j1)." @@\n";
|
69 |
+
foreach($group as $code) {
|
70 |
+
list($tag, $i1, $i2, $j1, $j2) = $code;
|
71 |
+
if($tag == 'equal') {
|
72 |
+
$diff .= ' '.implode("\n ", $this->diff->GetA($i1, $i2))."\n";
|
73 |
+
}
|
74 |
+
else {
|
75 |
+
if($tag == 'replace' || $tag == 'delete') {
|
76 |
+
$diff .= '-'.implode("\n-", $this->diff->GetA($i1, $i2))."\n";
|
77 |
+
}
|
78 |
+
|
79 |
+
if($tag == 'replace' || $tag == 'insert') {
|
80 |
+
$diff .= '+'.implode("\n+", $this->diff->GetB($j1, $j2))."\n";
|
81 |
+
}
|
82 |
+
}
|
83 |
+
}
|
84 |
+
}
|
85 |
+
return $diff;
|
86 |
+
}
|
87 |
}
|
libs/diff/SequenceMatcher.php
CHANGED
@@ -1,742 +1,742 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Sequence matcher for Diff
|
4 |
-
*
|
5 |
-
* PHP version 5
|
6 |
-
*
|
7 |
-
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
-
*
|
9 |
-
* All rights reserved.
|
10 |
-
*
|
11 |
-
* Redistribution and use in source and binary forms, with or without
|
12 |
-
* modification, are permitted provided that the following conditions are met:
|
13 |
-
*
|
14 |
-
* - Redistributions of source code must retain the above copyright notice,
|
15 |
-
* this list of conditions and the following disclaimer.
|
16 |
-
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
-
* this list of conditions and the following disclaimer in the documentation
|
18 |
-
* and/or other materials provided with the distribution.
|
19 |
-
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
-
* may be used to endorse or promote products derived from this software
|
21 |
-
* without specific prior written permission.
|
22 |
-
*
|
23 |
-
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
-
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
-
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
-
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
-
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
-
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
-
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
-
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
-
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
-
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
-
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
-
*
|
35 |
-
* @package Diff
|
36 |
-
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
-
* @copyright (c) 2009 Chris Boulton
|
38 |
-
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
-
* @version 1.1
|
40 |
-
* @link http://github.com/chrisboulton/php-diff
|
41 |
-
*/
|
42 |
-
|
43 |
-
class
|
44 |
-
{
|
45 |
-
/**
|
46 |
-
* @var string|array Either a string or an array containing a callback function to determine if a line is "junk" or not.
|
47 |
-
*/
|
48 |
-
private $junkCallback = null;
|
49 |
-
|
50 |
-
/**
|
51 |
-
* @var array The first sequence to compare against.
|
52 |
-
*/
|
53 |
-
private $a = null;
|
54 |
-
|
55 |
-
/**
|
56 |
-
* @var array The second sequence.
|
57 |
-
*/
|
58 |
-
private $b = null;
|
59 |
-
|
60 |
-
/**
|
61 |
-
* @var array Array of characters that are considered junk from the second sequence. Characters are the array key.
|
62 |
-
*/
|
63 |
-
private $junkDict = array();
|
64 |
-
|
65 |
-
/**
|
66 |
-
* @var array Array of indices that do not contain junk elements.
|
67 |
-
*/
|
68 |
-
private $b2j = array();
|
69 |
-
|
70 |
-
private $options = array();
|
71 |
-
|
72 |
-
private $defaultOptions = array(
|
73 |
-
'ignoreNewLines' => false,
|
74 |
-
'ignoreWhitespace' => false,
|
75 |
-
'ignoreCase' => false
|
76 |
-
);
|
77 |
-
|
78 |
-
/**
|
79 |
-
* The constructor. With the sequences being passed, they'll be set for the
|
80 |
-
* sequence matcher and it will perform a basic cleanup & calculate junk
|
81 |
-
* elements.
|
82 |
-
*
|
83 |
-
* @param string|array $a A string or array containing the lines to compare against.
|
84 |
-
* @param string|array $b A string or array containing the lines to compare.
|
85 |
-
* @param string|array $junkCallback Either an array or string that references a callback function (if there is one) to determine 'junk' characters.
|
86 |
-
*/
|
87 |
-
public function __construct($a, $b, $junkCallback=null, $options)
|
88 |
-
{
|
89 |
-
$this->a = null;
|
90 |
-
$this->b = null;
|
91 |
-
$this->junkCallback = $junkCallback;
|
92 |
-
$this->setOptions($options);
|
93 |
-
$this->setSequences($a, $b);
|
94 |
-
}
|
95 |
-
|
96 |
-
public function setOptions($options)
|
97 |
-
{
|
98 |
-
$this->options = array_merge($this->defaultOptions, $options);
|
99 |
-
}
|
100 |
-
|
101 |
-
/**
|
102 |
-
* Set the first and second sequences to use with the sequence matcher.
|
103 |
-
*
|
104 |
-
* @param string|array $a A string or array containing the lines to compare against.
|
105 |
-
* @param string|array $b A string or array containing the lines to compare.
|
106 |
-
*/
|
107 |
-
public function setSequences($a, $b)
|
108 |
-
{
|
109 |
-
$this->setSeq1($a);
|
110 |
-
$this->setSeq2($b);
|
111 |
-
}
|
112 |
-
|
113 |
-
/**
|
114 |
-
* Set the first sequence ($a) and reset any internal caches to indicate that
|
115 |
-
* when calling the calculation methods, we need to recalculate them.
|
116 |
-
*
|
117 |
-
* @param string|array $a The sequence to set as the first sequence.
|
118 |
-
*/
|
119 |
-
public function setSeq1($a)
|
120 |
-
{
|
121 |
-
if(!is_array($a)) {
|
122 |
-
$a = str_split($a);
|
123 |
-
}
|
124 |
-
if($a == $this->a) {
|
125 |
-
return;
|
126 |
-
}
|
127 |
-
|
128 |
-
$this->a= $a;
|
129 |
-
$this->matchingBlocks = null;
|
130 |
-
$this->opCodes = null;
|
131 |
-
}
|
132 |
-
|
133 |
-
/**
|
134 |
-
* Set the second sequence ($b) and reset any internal caches to indicate that
|
135 |
-
* when calling the calculation methods, we need to recalculate them.
|
136 |
-
*
|
137 |
-
* @param string|array $b The sequence to set as the second sequence.
|
138 |
-
*/
|
139 |
-
public function setSeq2($b)
|
140 |
-
{
|
141 |
-
if(!is_array($b)) {
|
142 |
-
$b = str_split($b);
|
143 |
-
}
|
144 |
-
if($b == $this->b) {
|
145 |
-
return;
|
146 |
-
}
|
147 |
-
|
148 |
-
$this->b = $b;
|
149 |
-
$this->matchingBlocks = null;
|
150 |
-
$this->opCodes = null;
|
151 |
-
$this->fullBCount = null;
|
152 |
-
$this->chainB();
|
153 |
-
}
|
154 |
-
|
155 |
-
/**
|
156 |
-
* Generate the internal arrays containing the list of junk and non-junk
|
157 |
-
* characters for the second ($b) sequence.
|
158 |
-
*/
|
159 |
-
private function chainB()
|
160 |
-
{
|
161 |
-
$length = count ($this->b);
|
162 |
-
$this->b2j = array();
|
163 |
-
$popularDict = array();
|
164 |
-
|
165 |
-
for($i = 0; $i < $length; ++$i) {
|
166 |
-
$char = $this->b[$i];
|
167 |
-
if(isset($this->b2j[$char])) {
|
168 |
-
if($length >= 200 && count($this->b2j[$char]) * 100 > $length) {
|
169 |
-
$popularDict[$char] = 1;
|
170 |
-
unset($this->b2j[$char]);
|
171 |
-
}
|
172 |
-
else {
|
173 |
-
$this->b2j[$char][] = $i;
|
174 |
-
}
|
175 |
-
}
|
176 |
-
else {
|
177 |
-
$this->b2j[$char] = array(
|
178 |
-
$i
|
179 |
-
);
|
180 |
-
}
|
181 |
-
}
|
182 |
-
|
183 |
-
// Remove leftovers
|
184 |
-
foreach(array_keys($popularDict) as $char) {
|
185 |
-
unset($this->b2j[$char]);
|
186 |
-
}
|
187 |
-
|
188 |
-
$this->junkDict = array();
|
189 |
-
if(is_callable($this->junkCallback)) {
|
190 |
-
foreach(array_keys($popularDict) as $char) {
|
191 |
-
if(call_user_func($this->junkCallback, $char)) {
|
192 |
-
$this->junkDict[$char] = 1;
|
193 |
-
unset($popularDict[$char]);
|
194 |
-
}
|
195 |
-
}
|
196 |
-
|
197 |
-
foreach(array_keys($this->b2j) as $char) {
|
198 |
-
if(call_user_func($this->junkCallback, $char)) {
|
199 |
-
$this->junkDict[$char] = 1;
|
200 |
-
unset($this->b2j[$char]);
|
201 |
-
}
|
202 |
-
}
|
203 |
-
}
|
204 |
-
}
|
205 |
-
|
206 |
-
/**
|
207 |
-
* Checks if a particular character is in the junk dictionary
|
208 |
-
* for the list of junk characters.
|
209 |
-
*
|
210 |
-
* @return boolean $b True if the character is considered junk. False if not.
|
211 |
-
*/
|
212 |
-
private function isBJunk($b)
|
213 |
-
{
|
214 |
-
if(isset($this->juncDict[$b])) {
|
215 |
-
return true;
|
216 |
-
}
|
217 |
-
|
218 |
-
return false;
|
219 |
-
}
|
220 |
-
|
221 |
-
/**
|
222 |
-
* Find the longest matching block in the two sequences, as defined by the
|
223 |
-
* lower and upper constraints for each sequence. (for the first sequence,
|
224 |
-
* $alo - $ahi and for the second sequence, $blo - $bhi)
|
225 |
-
*
|
226 |
-
* Essentially, of all of the maximal matching blocks, return the one that
|
227 |
-
* startest earliest in $a, and all of those maximal matching blocks that
|
228 |
-
* start earliest in $a, return the one that starts earliest in $b.
|
229 |
-
*
|
230 |
-
* If the junk callback is defined, do the above but with the restriction
|
231 |
-
* that the junk element appears in the block. Extend it as far as possible
|
232 |
-
* by matching only junk elements in both $a and $b.
|
233 |
-
*
|
234 |
-
* @param int $alo The lower constraint for the first sequence.
|
235 |
-
* @param int $ahi The upper constraint for the first sequence.
|
236 |
-
* @param int $blo The lower constraint for the second sequence.
|
237 |
-
* @param int $bhi The upper constraint for the second sequence.
|
238 |
-
* @return array Array containing the longest match that includes the starting position in $a, start in $b and the length/size.
|
239 |
-
*/
|
240 |
-
public function findLongestMatch($alo, $ahi, $blo, $bhi)
|
241 |
-
{
|
242 |
-
$a = $this->a;
|
243 |
-
$b = $this->b;
|
244 |
-
|
245 |
-
$bestI = $alo;
|
246 |
-
$bestJ = $blo;
|
247 |
-
$bestSize = 0;
|
248 |
-
|
249 |
-
$j2Len = array();
|
250 |
-
$nothing = array();
|
251 |
-
|
252 |
-
for($i = $alo; $i < $ahi; ++$i) {
|
253 |
-
$newJ2Len = array();
|
254 |
-
$jDict = $this->arrayGetDefault($this->b2j, $a[$i], $nothing);
|
255 |
-
foreach($jDict as $jKey => $j) {
|
256 |
-
if($j < $blo) {
|
257 |
-
continue;
|
258 |
-
}
|
259 |
-
else if($j >= $bhi) {
|
260 |
-
break;
|
261 |
-
}
|
262 |
-
|
263 |
-
$k = $this->arrayGetDefault($j2Len, $j -1, 0) + 1;
|
264 |
-
$newJ2Len[$j] = $k;
|
265 |
-
if($k > $bestSize) {
|
266 |
-
$bestI = $i - $k + 1;
|
267 |
-
$bestJ = $j - $k + 1;
|
268 |
-
$bestSize = $k;
|
269 |
-
}
|
270 |
-
}
|
271 |
-
|
272 |
-
$j2Len = $newJ2Len;
|
273 |
-
}
|
274 |
-
|
275 |
-
while($bestI > $alo && $bestJ > $blo && !$this->isBJunk($b[$bestJ - 1]) &&
|
276 |
-
!$this->linesAreDifferent($bestI - 1, $bestJ - 1)) {
|
277 |
-
--$bestI;
|
278 |
-
--$bestJ;
|
279 |
-
++$bestSize;
|
280 |
-
}
|
281 |
-
|
282 |
-
while($bestI + $bestSize < $ahi && ($bestJ + $bestSize) < $bhi &&
|
283 |
-
!$this->isBJunk($b[$bestJ + $bestSize]) && !$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize)) {
|
284 |
-
++$bestSize;
|
285 |
-
}
|
286 |
-
|
287 |
-
while($bestI > $alo && $bestJ > $blo && $this->isBJunk($b[$bestJ - 1]) &&
|
288 |
-
!$this->isLineDifferent($bestI - 1, $bestJ - 1)) {
|
289 |
-
--$bestI;
|
290 |
-
--$bestJ;
|
291 |
-
++$bestSize;
|
292 |
-
}
|
293 |
-
|
294 |
-
while($bestI + $bestSize < $ahi && $bestJ + $bestSize < $bhi &&
|
295 |
-
$this->isBJunk($b[$bestJ + $bestSize]) && !$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize)) {
|
296 |
-
++$bestSize;
|
297 |
-
}
|
298 |
-
|
299 |
-
return array(
|
300 |
-
$bestI,
|
301 |
-
$bestJ,
|
302 |
-
$bestSize
|
303 |
-
);
|
304 |
-
}
|
305 |
-
|
306 |
-
/**
|
307 |
-
* Check if the two lines at the given indexes are different or not.
|
308 |
-
*
|
309 |
-
* @param int $aIndex Line number to check against in a.
|
310 |
-
* @param int $bIndex Line number to check against in b.
|
311 |
-
* @return boolean True if the lines are different and false if not.
|
312 |
-
*/
|
313 |
-
public function linesAreDifferent($aIndex, $bIndex)
|
314 |
-
{
|
315 |
-
$lineA = $this->a[$aIndex];
|
316 |
-
$lineB = $this->b[$bIndex];
|
317 |
-
|
318 |
-
if($this->options['ignoreWhitespace']) {
|
319 |
-
$replace = array("\t", ' ');
|
320 |
-
$lineA = str_replace($replace, '', $lineA);
|
321 |
-
$lineB = str_replace($replace, '', $lineB);
|
322 |
-
}
|
323 |
-
|
324 |
-
if($this->options['ignoreCase']) {
|
325 |
-
$lineA = strtolower($lineA);
|
326 |
-
$lineB = strtolower($lineB);
|
327 |
-
}
|
328 |
-
|
329 |
-
if($lineA != $lineB) {
|
330 |
-
return true;
|
331 |
-
}
|
332 |
-
|
333 |
-
return false;
|
334 |
-
}
|
335 |
-
|
336 |
-
/**
|
337 |
-
* Return a nested set of arrays for all of the matching sub-sequences
|
338 |
-
* in the strings $a and $b.
|
339 |
-
*
|
340 |
-
* Each block contains the lower constraint of the block in $a, the lower
|
341 |
-
* constraint of the block in $b and finally the number of lines that the
|
342 |
-
* block continues for.
|
343 |
-
*
|
344 |
-
* @return array Nested array of the matching blocks, as described by the function.
|
345 |
-
*/
|
346 |
-
public function getMatchingBlocks()
|
347 |
-
{
|
348 |
-
if(!empty($this->matchingBlocks)) {
|
349 |
-
return $this->matchingBlocks;
|
350 |
-
}
|
351 |
-
|
352 |
-
$aLength = count($this->a);
|
353 |
-
$bLength = count($this->b);
|
354 |
-
|
355 |
-
$queue = array(
|
356 |
-
array(
|
357 |
-
0,
|
358 |
-
$aLength,
|
359 |
-
0,
|
360 |
-
$bLength
|
361 |
-
)
|
362 |
-
);
|
363 |
-
|
364 |
-
$matchingBlocks = array();
|
365 |
-
while(!empty($queue)) {
|
366 |
-
list($alo, $ahi, $blo, $bhi) = array_pop($queue);
|
367 |
-
$x = $this->findLongestMatch($alo, $ahi, $blo, $bhi);
|
368 |
-
list($i, $j, $k) = $x;
|
369 |
-
if($k) {
|
370 |
-
$matchingBlocks[] = $x;
|
371 |
-
if($alo < $i && $blo < $j) {
|
372 |
-
$queue[] = array(
|
373 |
-
$alo,
|
374 |
-
$i,
|
375 |
-
$blo,
|
376 |
-
$j
|
377 |
-
);
|
378 |
-
}
|
379 |
-
|
380 |
-
if($i + $k < $ahi && $j + $k < $bhi) {
|
381 |
-
$queue[] = array(
|
382 |
-
$i + $k,
|
383 |
-
$ahi,
|
384 |
-
$j + $k,
|
385 |
-
$bhi
|
386 |
-
);
|
387 |
-
}
|
388 |
-
}
|
389 |
-
}
|
390 |
-
|
391 |
-
usort($matchingBlocks, array($this, 'tupleSort'));
|
392 |
-
|
393 |
-
$i1 = 0;
|
394 |
-
$j1 = 0;
|
395 |
-
$k1 = 0;
|
396 |
-
$nonAdjacent = array();
|
397 |
-
foreach($matchingBlocks as $block) {
|
398 |
-
list($i2, $j2, $k2) = $block;
|
399 |
-
if($i1 + $k1 == $i2 && $j1 + $k1 == $j2) {
|
400 |
-
$k1 += $k2;
|
401 |
-
}
|
402 |
-
else {
|
403 |
-
if($k1) {
|
404 |
-
$nonAdjacent[] = array(
|
405 |
-
$i1,
|
406 |
-
$j1,
|
407 |
-
$k1
|
408 |
-
);
|
409 |
-
}
|
410 |
-
|
411 |
-
$i1 = $i2;
|
412 |
-
$j1 = $j2;
|
413 |
-
$k1 = $k2;
|
414 |
-
}
|
415 |
-
}
|
416 |
-
|
417 |
-
if($k1) {
|
418 |
-
$nonAdjacent[] = array(
|
419 |
-
$i1,
|
420 |
-
$j1,
|
421 |
-
$k1
|
422 |
-
);
|
423 |
-
}
|
424 |
-
|
425 |
-
$nonAdjacent[] = array(
|
426 |
-
$aLength,
|
427 |
-
$bLength,
|
428 |
-
0
|
429 |
-
);
|
430 |
-
|
431 |
-
$this->matchingBlocks = $nonAdjacent;
|
432 |
-
return $this->matchingBlocks;
|
433 |
-
}
|
434 |
-
|
435 |
-
/**
|
436 |
-
* Return a list of all of the opcodes for the differences between the
|
437 |
-
* two strings.
|
438 |
-
*
|
439 |
-
* The nested array returned contains an array describing the opcode
|
440 |
-
* which includes:
|
441 |
-
* 0 - The type of tag (as described below) for the opcode.
|
442 |
-
* 1 - The beginning line in the first sequence.
|
443 |
-
* 2 - The end line in the first sequence.
|
444 |
-
* 3 - The beginning line in the second sequence.
|
445 |
-
* 4 - The end line in the second sequence.
|
446 |
-
*
|
447 |
-
* The different types of tags include:
|
448 |
-
* replace - The string from $i1 to $i2 in $a should be replaced by
|
449 |
-
* the string in $b from $j1 to $j2.
|
450 |
-
* delete - The string in $a from $i1 to $j2 should be deleted.
|
451 |
-
* insert - The string in $b from $j1 to $j2 should be inserted at
|
452 |
-
* $i1 in $a.
|
453 |
-
* equal - The two strings with the specified ranges are equal.
|
454 |
-
*
|
455 |
-
* @return array Array of the opcodes describing the differences between the strings.
|
456 |
-
*/
|
457 |
-
public function getOpCodes()
|
458 |
-
{
|
459 |
-
if(!empty($this->opCodes)) {
|
460 |
-
return $this->opCodes;
|
461 |
-
}
|
462 |
-
|
463 |
-
$i = 0;
|
464 |
-
$j = 0;
|
465 |
-
$this->opCodes = array();
|
466 |
-
|
467 |
-
$blocks = $this->getMatchingBlocks();
|
468 |
-
foreach($blocks as $block) {
|
469 |
-
list($ai, $bj, $size) = $block;
|
470 |
-
$tag = '';
|
471 |
-
if($i < $ai && $j < $bj) {
|
472 |
-
$tag = 'replace';
|
473 |
-
}
|
474 |
-
else if($i < $ai) {
|
475 |
-
$tag = 'delete';
|
476 |
-
}
|
477 |
-
else if($j < $bj) {
|
478 |
-
$tag = 'insert';
|
479 |
-
}
|
480 |
-
|
481 |
-
if($tag) {
|
482 |
-
$this->opCodes[] = array(
|
483 |
-
$tag,
|
484 |
-
$i,
|
485 |
-
$ai,
|
486 |
-
$j,
|
487 |
-
$bj
|
488 |
-
);
|
489 |
-
}
|
490 |
-
|
491 |
-
$i = $ai + $size;
|
492 |
-
$j = $bj + $size;
|
493 |
-
|
494 |
-
if($size) {
|
495 |
-
$this->opCodes[] = array(
|
496 |
-
'equal',
|
497 |
-
$ai,
|
498 |
-
$i,
|
499 |
-
$bj,
|
500 |
-
$j
|
501 |
-
);
|
502 |
-
}
|
503 |
-
}
|
504 |
-
return $this->opCodes;
|
505 |
-
}
|
506 |
-
|
507 |
-
/**
|
508 |
-
* Return a series of nested arrays containing different groups of generated
|
509 |
-
* opcodes for the differences between the strings with up to $context lines
|
510 |
-
* of surrounding content.
|
511 |
-
*
|
512 |
-
* Essentially what happens here is any big equal blocks of strings are stripped
|
513 |
-
* out, the smaller subsets of changes are then arranged in to their groups.
|
514 |
-
* This means that the sequence matcher and diffs do not need to include the full
|
515 |
-
* content of the different files but can still provide context as to where the
|
516 |
-
* changes are.
|
517 |
-
*
|
518 |
-
* @param int $context The number of lines of context to provide around the groups.
|
519 |
-
* @return array Nested array of all of the grouped opcodes.
|
520 |
-
*/
|
521 |
-
public function getGroupedOpcodes($context=3)
|
522 |
-
{
|
523 |
-
$opCodes = $this->getOpCodes();
|
524 |
-
if(empty($opCodes)) {
|
525 |
-
$opCodes = array(
|
526 |
-
array(
|
527 |
-
'equal',
|
528 |
-
0,
|
529 |
-
1,
|
530 |
-
0,
|
531 |
-
1
|
532 |
-
)
|
533 |
-
);
|
534 |
-
}
|
535 |
-
|
536 |
-
if($opCodes[0][0] == 'equal') {
|
537 |
-
$opCodes[0] = array(
|
538 |
-
$opCodes[0][0],
|
539 |
-
max($opCodes[0][1], $opCodes[0][2] - $context),
|
540 |
-
$opCodes[0][2],
|
541 |
-
max($opCodes[0][3], $opCodes[0][4] - $context),
|
542 |
-
$opCodes[0][4]
|
543 |
-
);
|
544 |
-
}
|
545 |
-
|
546 |
-
$lastItem = count($opCodes) - 1;
|
547 |
-
if($opCodes[$lastItem][0] == 'equal') {
|
548 |
-
list($tag, $i1, $i2, $j1, $j2) = $opCodes[$lastItem];
|
549 |
-
$opCodes[$lastItem] = array(
|
550 |
-
$tag,
|
551 |
-
$i1,
|
552 |
-
min($i2, $i1 + $context),
|
553 |
-
$j1,
|
554 |
-
min($j2, $j1 + $context)
|
555 |
-
);
|
556 |
-
}
|
557 |
-
|
558 |
-
$maxRange = $context * 2;
|
559 |
-
$groups = array();
|
560 |
-
$group = array();
|
561 |
-
foreach($opCodes as $code) {
|
562 |
-
list($tag, $i1, $i2, $j1, $j2) = $code;
|
563 |
-
if($tag == 'equal' && $i2 - $i1 > $maxRange) {
|
564 |
-
$group[] = array(
|
565 |
-
$tag,
|
566 |
-
$i1,
|
567 |
-
min($i2, $i1 + $context),
|
568 |
-
$j1,
|
569 |
-
min($j2, $j1 + $context)
|
570 |
-
);
|
571 |
-
$groups[] = $group;
|
572 |
-
$group = array();
|
573 |
-
$i1 = max($i1, $i2 - $context);
|
574 |
-
$j1 = max($j1, $j2 - $context);
|
575 |
-
}
|
576 |
-
$group[] = array(
|
577 |
-
$tag,
|
578 |
-
$i1,
|
579 |
-
$i2,
|
580 |
-
$j1,
|
581 |
-
$j2
|
582 |
-
);
|
583 |
-
}
|
584 |
-
|
585 |
-
if(!empty($group) && !(count($group) == 1 && $group[0][0] == 'equal')) {
|
586 |
-
$groups[] = $group;
|
587 |
-
}
|
588 |
-
|
589 |
-
return $groups;
|
590 |
-
}
|
591 |
-
|
592 |
-
/**
|
593 |
-
* Return a measure of the similarity between the two sequences.
|
594 |
-
* This will be a float value between 0 and 1.
|
595 |
-
*
|
596 |
-
* Out of all of the ratio calculation functions, this is the most
|
597 |
-
* expensive to call if getMatchingBlocks or getOpCodes is yet to be
|
598 |
-
* called. The other calculation methods (quickRatio and realquickRatio)
|
599 |
-
* can be used to perform quicker calculations but may be less accurate.
|
600 |
-
*
|
601 |
-
* The ratio is calculated as (2 * number of matches) / total number of
|
602 |
-
* elements in both sequences.
|
603 |
-
*
|
604 |
-
* @return float The calculated ratio.
|
605 |
-
*/
|
606 |
-
public function Ratio()
|
607 |
-
{
|
608 |
-
$matches = array_reduce($this->getMatchingBlocks(), array($this, 'ratioReduce'), 0);
|
609 |
-
return $this->calculateRatio($matches, count ($this->a) + count ($this->b));
|
610 |
-
}
|
611 |
-
|
612 |
-
/**
|
613 |
-
* Helper function to calculate the number of matches for Ratio().
|
614 |
-
*
|
615 |
-
* @param int $sum The running total for the number of matches.
|
616 |
-
* @param array $triple Array containing the matching block triple to add to the running total.
|
617 |
-
* @return int The new running total for the number of matches.
|
618 |
-
*/
|
619 |
-
private function ratioReduce($sum, $triple)
|
620 |
-
{
|
621 |
-
return $sum + ($triple[count($triple) - 1]);
|
622 |
-
}
|
623 |
-
|
624 |
-
/**
|
625 |
-
* Quickly return an upper bound ratio for the similarity of the strings.
|
626 |
-
* This is quicker to compute than Ratio().
|
627 |
-
*
|
628 |
-
* @return float The calculated ratio.
|
629 |
-
*/
|
630 |
-
private function quickRatio()
|
631 |
-
{
|
632 |
-
if($this->fullBCount === null) {
|
633 |
-
$this->fullBCount = array();
|
634 |
-
$bLength = count ($b);
|
635 |
-
for($i = 0; $i < $bLength; ++$i) {
|
636 |
-
$char = $this->b[$i];
|
637 |
-
$this->fullBCount[$char] = $this->arrayGetDefault($this->fullBCount, $char, 0) + 1;
|
638 |
-
}
|
639 |
-
}
|
640 |
-
|
641 |
-
$avail = array();
|
642 |
-
$matches = 0;
|
643 |
-
$aLength = count ($this->a);
|
644 |
-
for($i = 0; $i < $aLength; ++$i) {
|
645 |
-
$char = $this->a[$i];
|
646 |
-
if(isset($avail[$char])) {
|
647 |
-
$numb = $avail[$char];
|
648 |
-
}
|
649 |
-
else {
|
650 |
-
$numb = $this->arrayGetDefault($this->fullBCount, $char, 0);
|
651 |
-
}
|
652 |
-
$avail[$char] = $numb - 1;
|
653 |
-
if($numb > 0) {
|
654 |
-
++$matches;
|
655 |
-
}
|
656 |
-
}
|
657 |
-
|
658 |
-
$this->calculateRatio($matches, count ($this->a) + count ($this->b));
|
659 |
-
}
|
660 |
-
|
661 |
-
/**
|
662 |
-
* Return an upper bound ratio really quickly for the similarity of the strings.
|
663 |
-
* This is quicker to compute than Ratio() and quickRatio().
|
664 |
-
*
|
665 |
-
* @return float The calculated ratio.
|
666 |
-
*/
|
667 |
-
private function realquickRatio()
|
668 |
-
{
|
669 |
-
$aLength = count ($this->a);
|
670 |
-
$bLength = count ($this->b);
|
671 |
-
|
672 |
-
return $this->calculateRatio(min($aLength, $bLength), $aLength + $bLength);
|
673 |
-
}
|
674 |
-
|
675 |
-
/**
|
676 |
-
* Helper function for calculating the ratio to measure similarity for the strings.
|
677 |
-
* The ratio is defined as being 2 * (number of matches / total length)
|
678 |
-
*
|
679 |
-
* @param int $matches The number of matches in the two strings.
|
680 |
-
* @param int $length The length of the two strings.
|
681 |
-
* @return float The calculated ratio.
|
682 |
-
*/
|
683 |
-
private function calculateRatio($matches, $length=0)
|
684 |
-
{
|
685 |
-
if($length) {
|
686 |
-
return 2 * ($matches / $length);
|
687 |
-
}
|
688 |
-
else {
|
689 |
-
return 1;
|
690 |
-
}
|
691 |
-
}
|
692 |
-
|
693 |
-
/**
|
694 |
-
* Helper function that provides the ability to return the value for a key
|
695 |
-
* in an array of it exists, or if it doesn't then return a default value.
|
696 |
-
* Essentially cleaner than doing a series of if(isset()) {} else {} calls.
|
697 |
-
*
|
698 |
-
* @param array $array The array to search.
|
699 |
-
* @param string $key The key to check that exists.
|
700 |
-
* @param mixed $default The value to return as the default value if the key doesn't exist.
|
701 |
-
* @return mixed The value from the array if the key exists or otherwise the default.
|
702 |
-
*/
|
703 |
-
private function arrayGetDefault($array, $key, $default)
|
704 |
-
{
|
705 |
-
if(isset($array[$key])) {
|
706 |
-
return $array[$key];
|
707 |
-
}
|
708 |
-
else {
|
709 |
-
return $default;
|
710 |
-
}
|
711 |
-
}
|
712 |
-
|
713 |
-
/**
|
714 |
-
* Sort an array by the nested arrays it contains. Helper function for getMatchingBlocks
|
715 |
-
*
|
716 |
-
* @param array $a First array to compare.
|
717 |
-
* @param array $b Second array to compare.
|
718 |
-
* @return int -1, 0 or 1, as expected by the usort function.
|
719 |
-
*/
|
720 |
-
private function tupleSort($a, $b)
|
721 |
-
{
|
722 |
-
$max = max(count($a), count($b));
|
723 |
-
for($i = 0; $i < $max; ++$i) {
|
724 |
-
if($a[$i] < $b[$i]) {
|
725 |
-
return -1;
|
726 |
-
}
|
727 |
-
else if($a[$i] > $b[$i]) {
|
728 |
-
return 1;
|
729 |
-
}
|
730 |
-
}
|
731 |
-
|
732 |
-
if(count($a) == $count($b)) {
|
733 |
-
return 0;
|
734 |
-
}
|
735 |
-
else if(count($a) < count($b)) {
|
736 |
-
return -1;
|
737 |
-
}
|
738 |
-
else {
|
739 |
-
return 1;
|
740 |
-
}
|
741 |
-
}
|
742 |
}
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Sequence matcher for Diff
|
4 |
+
*
|
5 |
+
* PHP version 5
|
6 |
+
*
|
7 |
+
* Copyright (c) 2009 Chris Boulton <chris.boulton@interspire.com>
|
8 |
+
*
|
9 |
+
* All rights reserved.
|
10 |
+
*
|
11 |
+
* Redistribution and use in source and binary forms, with or without
|
12 |
+
* modification, are permitted provided that the following conditions are met:
|
13 |
+
*
|
14 |
+
* - Redistributions of source code must retain the above copyright notice,
|
15 |
+
* this list of conditions and the following disclaimer.
|
16 |
+
* - Redistributions in binary form must reproduce the above copyright notice,
|
17 |
+
* this list of conditions and the following disclaimer in the documentation
|
18 |
+
* and/or other materials provided with the distribution.
|
19 |
+
* - Neither the name of the Chris Boulton nor the names of its contributors
|
20 |
+
* may be used to endorse or promote products derived from this software
|
21 |
+
* without specific prior written permission.
|
22 |
+
*
|
23 |
+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
24 |
+
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
25 |
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
26 |
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
27 |
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
28 |
+
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
29 |
+
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
30 |
+
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
31 |
+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
32 |
+
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
33 |
+
* POSSIBILITY OF SUCH DAMAGE.
|
34 |
+
*
|
35 |
+
* @package Diff
|
36 |
+
* @author Chris Boulton <chris.boulton@interspire.com>
|
37 |
+
* @copyright (c) 2009 Chris Boulton
|
38 |
+
* @license New BSD License http://www.opensource.org/licenses/bsd-license.php
|
39 |
+
* @version 1.1
|
40 |
+
* @link http://github.com/chrisboulton/php-diff
|
41 |
+
*/
|
42 |
+
|
43 |
+
class WPR_Diff_SequenceMatcher
|
44 |
+
{
|
45 |
+
/**
|
46 |
+
* @var string|array Either a string or an array containing a callback function to determine if a line is "junk" or not.
|
47 |
+
*/
|
48 |
+
private $junkCallback = null;
|
49 |
+
|
50 |
+
/**
|
51 |
+
* @var array The first sequence to compare against.
|
52 |
+
*/
|
53 |
+
private $a = null;
|
54 |
+
|
55 |
+
/**
|
56 |
+
* @var array The second sequence.
|
57 |
+
*/
|
58 |
+
private $b = null;
|
59 |
+
|
60 |
+
/**
|
61 |
+
* @var array Array of characters that are considered junk from the second sequence. Characters are the array key.
|
62 |
+
*/
|
63 |
+
private $junkDict = array();
|
64 |
+
|
65 |
+
/**
|
66 |
+
* @var array Array of indices that do not contain junk elements.
|
67 |
+
*/
|
68 |
+
private $b2j = array();
|
69 |
+
|
70 |
+
private $options = array();
|
71 |
+
|
72 |
+
private $defaultOptions = array(
|
73 |
+
'ignoreNewLines' => false,
|
74 |
+
'ignoreWhitespace' => false,
|
75 |
+
'ignoreCase' => false
|
76 |
+
);
|
77 |
+
|
78 |
+
/**
|
79 |
+
* The constructor. With the sequences being passed, they'll be set for the
|
80 |
+
* sequence matcher and it will perform a basic cleanup & calculate junk
|
81 |
+
* elements.
|
82 |
+
*
|
83 |
+
* @param string|array $a A string or array containing the lines to compare against.
|
84 |
+
* @param string|array $b A string or array containing the lines to compare.
|
85 |
+
* @param string|array $junkCallback Either an array or string that references a callback function (if there is one) to determine 'junk' characters.
|
86 |
+
*/
|
87 |
+
public function __construct($a, $b, $junkCallback=null, $options)
|
88 |
+
{
|
89 |
+
$this->a = null;
|
90 |
+
$this->b = null;
|
91 |
+
$this->junkCallback = $junkCallback;
|
92 |
+
$this->setOptions($options);
|
93 |
+
$this->setSequences($a, $b);
|
94 |
+
}
|
95 |
+
|
96 |
+
public function setOptions($options)
|
97 |
+
{
|
98 |
+
$this->options = array_merge($this->defaultOptions, $options);
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Set the first and second sequences to use with the sequence matcher.
|
103 |
+
*
|
104 |
+
* @param string|array $a A string or array containing the lines to compare against.
|
105 |
+
* @param string|array $b A string or array containing the lines to compare.
|
106 |
+
*/
|
107 |
+
public function setSequences($a, $b)
|
108 |
+
{
|
109 |
+
$this->setSeq1($a);
|
110 |
+
$this->setSeq2($b);
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Set the first sequence ($a) and reset any internal caches to indicate that
|
115 |
+
* when calling the calculation methods, we need to recalculate them.
|
116 |
+
*
|
117 |
+
* @param string|array $a The sequence to set as the first sequence.
|
118 |
+
*/
|
119 |
+
public function setSeq1($a)
|
120 |
+
{
|
121 |
+
if(!is_array($a)) {
|
122 |
+
$a = str_split($a);
|
123 |
+
}
|
124 |
+
if($a == $this->a) {
|
125 |
+
return;
|
126 |
+
}
|
127 |
+
|
128 |
+
$this->a= $a;
|
129 |
+
$this->matchingBlocks = null;
|
130 |
+
$this->opCodes = null;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Set the second sequence ($b) and reset any internal caches to indicate that
|
135 |
+
* when calling the calculation methods, we need to recalculate them.
|
136 |
+
*
|
137 |
+
* @param string|array $b The sequence to set as the second sequence.
|
138 |
+
*/
|
139 |
+
public function setSeq2($b)
|
140 |
+
{
|
141 |
+
if(!is_array($b)) {
|
142 |
+
$b = str_split($b);
|
143 |
+
}
|
144 |
+
if($b == $this->b) {
|
145 |
+
return;
|
146 |
+
}
|
147 |
+
|
148 |
+
$this->b = $b;
|
149 |
+
$this->matchingBlocks = null;
|
150 |
+
$this->opCodes = null;
|
151 |
+
$this->fullBCount = null;
|
152 |
+
$this->chainB();
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Generate the internal arrays containing the list of junk and non-junk
|
157 |
+
* characters for the second ($b) sequence.
|
158 |
+
*/
|
159 |
+
private function chainB()
|
160 |
+
{
|
161 |
+
$length = count ($this->b);
|
162 |
+
$this->b2j = array();
|
163 |
+
$popularDict = array();
|
164 |
+
|
165 |
+
for($i = 0; $i < $length; ++$i) {
|
166 |
+
$char = $this->b[$i];
|
167 |
+
if(isset($this->b2j[$char])) {
|
168 |
+
if($length >= 200 && count($this->b2j[$char]) * 100 > $length) {
|
169 |
+
$popularDict[$char] = 1;
|
170 |
+
unset($this->b2j[$char]);
|
171 |
+
}
|
172 |
+
else {
|
173 |
+
$this->b2j[$char][] = $i;
|
174 |
+
}
|
175 |
+
}
|
176 |
+
else {
|
177 |
+
$this->b2j[$char] = array(
|
178 |
+
$i
|
179 |
+
);
|
180 |
+
}
|
181 |
+
}
|
182 |
+
|
183 |
+
// Remove leftovers
|
184 |
+
foreach(array_keys($popularDict) as $char) {
|
185 |
+
unset($this->b2j[$char]);
|
186 |
+
}
|
187 |
+
|
188 |
+
$this->junkDict = array();
|
189 |
+
if(is_callable($this->junkCallback)) {
|
190 |
+
foreach(array_keys($popularDict) as $char) {
|
191 |
+
if(call_user_func($this->junkCallback, $char)) {
|
192 |
+
$this->junkDict[$char] = 1;
|
193 |
+
unset($popularDict[$char]);
|
194 |
+
}
|
195 |
+
}
|
196 |
+
|
197 |
+
foreach(array_keys($this->b2j) as $char) {
|
198 |
+
if(call_user_func($this->junkCallback, $char)) {
|
199 |
+
$this->junkDict[$char] = 1;
|
200 |
+
unset($this->b2j[$char]);
|
201 |
+
}
|
202 |
+
}
|
203 |
+
}
|
204 |
+
}
|
205 |
+
|
206 |
+
/**
|
207 |
+
* Checks if a particular character is in the junk dictionary
|
208 |
+
* for the list of junk characters.
|
209 |
+
*
|
210 |
+
* @return boolean $b True if the character is considered junk. False if not.
|
211 |
+
*/
|
212 |
+
private function isBJunk($b)
|
213 |
+
{
|
214 |
+
if(isset($this->juncDict[$b])) {
|
215 |
+
return true;
|
216 |
+
}
|
217 |
+
|
218 |
+
return false;
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Find the longest matching block in the two sequences, as defined by the
|
223 |
+
* lower and upper constraints for each sequence. (for the first sequence,
|
224 |
+
* $alo - $ahi and for the second sequence, $blo - $bhi)
|
225 |
+
*
|
226 |
+
* Essentially, of all of the maximal matching blocks, return the one that
|
227 |
+
* startest earliest in $a, and all of those maximal matching blocks that
|
228 |
+
* start earliest in $a, return the one that starts earliest in $b.
|
229 |
+
*
|
230 |
+
* If the junk callback is defined, do the above but with the restriction
|
231 |
+
* that the junk element appears in the block. Extend it as far as possible
|
232 |
+
* by matching only junk elements in both $a and $b.
|
233 |
+
*
|
234 |
+
* @param int $alo The lower constraint for the first sequence.
|
235 |
+
* @param int $ahi The upper constraint for the first sequence.
|
236 |
+
* @param int $blo The lower constraint for the second sequence.
|
237 |
+
* @param int $bhi The upper constraint for the second sequence.
|
238 |
+
* @return array Array containing the longest match that includes the starting position in $a, start in $b and the length/size.
|
239 |
+
*/
|
240 |
+
public function findLongestMatch($alo, $ahi, $blo, $bhi)
|
241 |
+
{
|
242 |
+
$a = $this->a;
|
243 |
+
$b = $this->b;
|
244 |
+
|
245 |
+
$bestI = $alo;
|
246 |
+
$bestJ = $blo;
|
247 |
+
$bestSize = 0;
|
248 |
+
|
249 |
+
$j2Len = array();
|
250 |
+
$nothing = array();
|
251 |
+
|
252 |
+
for($i = $alo; $i < $ahi; ++$i) {
|
253 |
+
$newJ2Len = array();
|
254 |
+
$jDict = $this->arrayGetDefault($this->b2j, $a[$i], $nothing);
|
255 |
+
foreach($jDict as $jKey => $j) {
|
256 |
+
if($j < $blo) {
|
257 |
+
continue;
|
258 |
+
}
|
259 |
+
else if($j >= $bhi) {
|
260 |
+
break;
|
261 |
+
}
|
262 |
+
|
263 |
+
$k = $this->arrayGetDefault($j2Len, $j -1, 0) + 1;
|
264 |
+
$newJ2Len[$j] = $k;
|
265 |
+
if($k > $bestSize) {
|
266 |
+
$bestI = $i - $k + 1;
|
267 |
+
$bestJ = $j - $k + 1;
|
268 |
+
$bestSize = $k;
|
269 |
+
}
|
270 |
+
}
|
271 |
+
|
272 |
+
$j2Len = $newJ2Len;
|
273 |
+
}
|
274 |
+
|
275 |
+
while($bestI > $alo && $bestJ > $blo && !$this->isBJunk($b[$bestJ - 1]) &&
|
276 |
+
!$this->linesAreDifferent($bestI - 1, $bestJ - 1)) {
|
277 |
+
--$bestI;
|
278 |
+
--$bestJ;
|
279 |
+
++$bestSize;
|
280 |
+
}
|
281 |
+
|
282 |
+
while($bestI + $bestSize < $ahi && ($bestJ + $bestSize) < $bhi &&
|
283 |
+
!$this->isBJunk($b[$bestJ + $bestSize]) && !$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize)) {
|
284 |
+
++$bestSize;
|
285 |
+
}
|
286 |
+
|
287 |
+
while($bestI > $alo && $bestJ > $blo && $this->isBJunk($b[$bestJ - 1]) &&
|
288 |
+
!$this->isLineDifferent($bestI - 1, $bestJ - 1)) {
|
289 |
+
--$bestI;
|
290 |
+
--$bestJ;
|
291 |
+
++$bestSize;
|
292 |
+
}
|
293 |
+
|
294 |
+
while($bestI + $bestSize < $ahi && $bestJ + $bestSize < $bhi &&
|
295 |
+
$this->isBJunk($b[$bestJ + $bestSize]) && !$this->linesAreDifferent($bestI + $bestSize, $bestJ + $bestSize)) {
|
296 |
+
++$bestSize;
|
297 |
+
}
|
298 |
+
|
299 |
+
return array(
|
300 |
+
$bestI,
|
301 |
+
$bestJ,
|
302 |
+
$bestSize
|
303 |
+
);
|
304 |
+
}
|
305 |
+
|
306 |
+
/**
|
307 |
+
* Check if the two lines at the given indexes are different or not.
|
308 |
+
*
|
309 |
+
* @param int $aIndex Line number to check against in a.
|
310 |
+
* @param int $bIndex Line number to check against in b.
|
311 |
+
* @return boolean True if the lines are different and false if not.
|
312 |
+
*/
|
313 |
+
public function linesAreDifferent($aIndex, $bIndex)
|
314 |
+
{
|
315 |
+
$lineA = $this->a[$aIndex];
|
316 |
+
$lineB = $this->b[$bIndex];
|
317 |
+
|
318 |
+
if($this->options['ignoreWhitespace']) {
|
319 |
+
$replace = array("\t", ' ');
|
320 |
+
$lineA = str_replace($replace, '', $lineA);
|
321 |
+
$lineB = str_replace($replace, '', $lineB);
|
322 |
+
}
|
323 |
+
|
324 |
+
if($this->options['ignoreCase']) {
|
325 |
+
$lineA = strtolower($lineA);
|
326 |
+
$lineB = strtolower($lineB);
|
327 |
+
}
|
328 |
+
|
329 |
+
if($lineA != $lineB) {
|
330 |
+
return true;
|
331 |
+
}
|
332 |
+
|
333 |
+
return false;
|
334 |
+
}
|
335 |
+
|
336 |
+
/**
|
337 |
+
* Return a nested set of arrays for all of the matching sub-sequences
|
338 |
+
* in the strings $a and $b.
|
339 |
+
*
|
340 |
+
* Each block contains the lower constraint of the block in $a, the lower
|
341 |
+
* constraint of the block in $b and finally the number of lines that the
|
342 |
+
* block continues for.
|
343 |
+
*
|
344 |
+
* @return array Nested array of the matching blocks, as described by the function.
|
345 |
+
*/
|
346 |
+
public function getMatchingBlocks()
|
347 |
+
{
|
348 |
+
if(!empty($this->matchingBlocks)) {
|
349 |
+
return $this->matchingBlocks;
|
350 |
+
}
|
351 |
+
|
352 |
+
$aLength = count($this->a);
|
353 |
+
$bLength = count($this->b);
|
354 |
+
|
355 |
+
$queue = array(
|
356 |
+
array(
|
357 |
+
0,
|
358 |
+
$aLength,
|
359 |
+
0,
|
360 |
+
$bLength
|
361 |
+
)
|
362 |
+
);
|
363 |
+
|
364 |
+
$matchingBlocks = array();
|
365 |
+
while(!empty($queue)) {
|
366 |
+
list($alo, $ahi, $blo, $bhi) = array_pop($queue);
|
367 |
+
$x = $this->findLongestMatch($alo, $ahi, $blo, $bhi);
|
368 |
+
list($i, $j, $k) = $x;
|
369 |
+
if($k) {
|
370 |
+
$matchingBlocks[] = $x;
|
371 |
+
if($alo < $i && $blo < $j) {
|
372 |
+
$queue[] = array(
|
373 |
+
$alo,
|
374 |
+
$i,
|
375 |
+
$blo,
|
376 |
+
$j
|
377 |
+
);
|
378 |
+
}
|
379 |
+
|
380 |
+
if($i + $k < $ahi && $j + $k < $bhi) {
|
381 |
+
$queue[] = array(
|
382 |
+
$i + $k,
|
383 |
+
$ahi,
|
384 |
+
$j + $k,
|
385 |
+
$bhi
|
386 |
+
);
|
387 |
+
}
|
388 |
+
}
|
389 |
+
}
|
390 |
+
|
391 |
+
usort($matchingBlocks, array($this, 'tupleSort'));
|
392 |
+
|
393 |
+
$i1 = 0;
|
394 |
+
$j1 = 0;
|
395 |
+
$k1 = 0;
|
396 |
+
$nonAdjacent = array();
|
397 |
+
foreach($matchingBlocks as $block) {
|
398 |
+
list($i2, $j2, $k2) = $block;
|
399 |
+
if($i1 + $k1 == $i2 && $j1 + $k1 == $j2) {
|
400 |
+
$k1 += $k2;
|
401 |
+
}
|
402 |
+
else {
|
403 |
+
if($k1) {
|
404 |
+
$nonAdjacent[] = array(
|
405 |
+
$i1,
|
406 |
+
$j1,
|
407 |
+
$k1
|
408 |
+
);
|
409 |
+
}
|
410 |
+
|
411 |
+
$i1 = $i2;
|
412 |
+
$j1 = $j2;
|
413 |
+
$k1 = $k2;
|
414 |
+
}
|
415 |
+
}
|
416 |
+
|
417 |
+
if($k1) {
|
418 |
+
$nonAdjacent[] = array(
|
419 |
+
$i1,
|
420 |
+
$j1,
|
421 |
+
$k1
|
422 |
+
);
|
423 |
+
}
|
424 |
+
|
425 |
+
$nonAdjacent[] = array(
|
426 |
+
$aLength,
|
427 |
+
$bLength,
|
428 |
+
0
|
429 |
+
);
|
430 |
+
|
431 |
+
$this->matchingBlocks = $nonAdjacent;
|
432 |
+
return $this->matchingBlocks;
|
433 |
+
}
|
434 |
+
|
435 |
+
/**
|
436 |
+
* Return a list of all of the opcodes for the differences between the
|
437 |
+
* two strings.
|
438 |
+
*
|
439 |
+
* The nested array returned contains an array describing the opcode
|
440 |
+
* which includes:
|
441 |
+
* 0 - The type of tag (as described below) for the opcode.
|
442 |
+
* 1 - The beginning line in the first sequence.
|
443 |
+
* 2 - The end line in the first sequence.
|
444 |
+
* 3 - The beginning line in the second sequence.
|
445 |
+
* 4 - The end line in the second sequence.
|
446 |
+
*
|
447 |
+
* The different types of tags include:
|
448 |
+
* replace - The string from $i1 to $i2 in $a should be replaced by
|
449 |
+
* the string in $b from $j1 to $j2.
|
450 |
+
* delete - The string in $a from $i1 to $j2 should be deleted.
|
451 |
+
* insert - The string in $b from $j1 to $j2 should be inserted at
|
452 |
+
* $i1 in $a.
|
453 |
+
* equal - The two strings with the specified ranges are equal.
|
454 |
+
*
|
455 |
+
* @return array Array of the opcodes describing the differences between the strings.
|
456 |
+
*/
|
457 |
+
public function getOpCodes()
|
458 |
+
{
|
459 |
+
if(!empty($this->opCodes)) {
|
460 |
+
return $this->opCodes;
|
461 |
+
}
|
462 |
+
|
463 |
+
$i = 0;
|
464 |
+
$j = 0;
|
465 |
+
$this->opCodes = array();
|
466 |
+
|
467 |
+
$blocks = $this->getMatchingBlocks();
|
468 |
+
foreach($blocks as $block) {
|
469 |
+
list($ai, $bj, $size) = $block;
|
470 |
+
$tag = '';
|
471 |
+
if($i < $ai && $j < $bj) {
|
472 |
+
$tag = 'replace';
|
473 |
+
}
|
474 |
+
else if($i < $ai) {
|
475 |
+
$tag = 'delete';
|
476 |
+
}
|
477 |
+
else if($j < $bj) {
|
478 |
+
$tag = 'insert';
|
479 |
+
}
|
480 |
+
|
481 |
+
if($tag) {
|
482 |
+
$this->opCodes[] = array(
|
483 |
+
$tag,
|
484 |
+
$i,
|
485 |
+
$ai,
|
486 |
+
$j,
|
487 |
+
$bj
|
488 |
+
);
|
489 |
+
}
|
490 |
+
|
491 |
+
$i = $ai + $size;
|
492 |
+
$j = $bj + $size;
|
493 |
+
|
494 |
+
if($size) {
|
495 |
+
$this->opCodes[] = array(
|
496 |
+
'equal',
|
497 |
+
$ai,
|
498 |
+
$i,
|
499 |
+
$bj,
|
500 |
+
$j
|
501 |
+
);
|
502 |
+
}
|
503 |
+
}
|
504 |
+
return $this->opCodes;
|
505 |
+
}
|
506 |
+
|
507 |
+
/**
|
508 |
+
* Return a series of nested arrays containing different groups of generated
|
509 |
+
* opcodes for the differences between the strings with up to $context lines
|
510 |
+
* of surrounding content.
|
511 |
+
*
|
512 |
+
* Essentially what happens here is any big equal blocks of strings are stripped
|
513 |
+
* out, the smaller subsets of changes are then arranged in to their groups.
|
514 |
+
* This means that the sequence matcher and diffs do not need to include the full
|
515 |
+
* content of the different files but can still provide context as to where the
|
516 |
+
* changes are.
|
517 |
+
*
|
518 |
+
* @param int $context The number of lines of context to provide around the groups.
|
519 |
+
* @return array Nested array of all of the grouped opcodes.
|
520 |
+
*/
|
521 |
+
public function getGroupedOpcodes($context=3)
|
522 |
+
{
|
523 |
+
$opCodes = $this->getOpCodes();
|
524 |
+
if(empty($opCodes)) {
|
525 |
+
$opCodes = array(
|
526 |
+
array(
|
527 |
+
'equal',
|
528 |
+
0,
|
529 |
+
1,
|
530 |
+
0,
|
531 |
+
1
|
532 |
+
)
|
533 |
+
);
|
534 |
+
}
|
535 |
+
|
536 |
+
if($opCodes[0][0] == 'equal') {
|
537 |
+
$opCodes[0] = array(
|
538 |
+
$opCodes[0][0],
|
539 |
+
max($opCodes[0][1], $opCodes[0][2] - $context),
|
540 |
+
$opCodes[0][2],
|
541 |
+
max($opCodes[0][3], $opCodes[0][4] - $context),
|
542 |
+
$opCodes[0][4]
|
543 |
+
);
|
544 |
+
}
|
545 |
+
|
546 |
+
$lastItem = count($opCodes) - 1;
|
547 |
+
if($opCodes[$lastItem][0] == 'equal') {
|
548 |
+
list($tag, $i1, $i2, $j1, $j2) = $opCodes[$lastItem];
|
549 |
+
$opCodes[$lastItem] = array(
|
550 |
+
$tag,
|
551 |
+
$i1,
|
552 |
+
min($i2, $i1 + $context),
|
553 |
+
$j1,
|
554 |
+
min($j2, $j1 + $context)
|
555 |
+
);
|
556 |
+
}
|
557 |
+
|
558 |
+
$maxRange = $context * 2;
|
559 |
+
$groups = array();
|
560 |
+
$group = array();
|
561 |
+
foreach($opCodes as $code) {
|
562 |
+
list($tag, $i1, $i2, $j1, $j2) = $code;
|
563 |
+
if($tag == 'equal' && $i2 - $i1 > $maxRange) {
|
564 |
+
$group[] = array(
|
565 |
+
$tag,
|
566 |
+
$i1,
|
567 |
+
min($i2, $i1 + $context),
|
568 |
+
$j1,
|
569 |
+
min($j2, $j1 + $context)
|
570 |
+
);
|
571 |
+
$groups[] = $group;
|
572 |
+
$group = array();
|
573 |
+
$i1 = max($i1, $i2 - $context);
|
574 |
+
$j1 = max($j1, $j2 - $context);
|
575 |
+
}
|
576 |
+
$group[] = array(
|
577 |
+
$tag,
|
578 |
+
$i1,
|
579 |
+
$i2,
|
580 |
+
$j1,
|
581 |
+
$j2
|
582 |
+
);
|
583 |
+
}
|
584 |
+
|
585 |
+
if(!empty($group) && !(count($group) == 1 && $group[0][0] == 'equal')) {
|
586 |
+
$groups[] = $group;
|
587 |
+
}
|
588 |
+
|
589 |
+
return $groups;
|
590 |
+
}
|
591 |
+
|
592 |
+
/**
|
593 |
+
* Return a measure of the similarity between the two sequences.
|
594 |
+
* This will be a float value between 0 and 1.
|
595 |
+
*
|
596 |
+
* Out of all of the ratio calculation functions, this is the most
|
597 |
+
* expensive to call if getMatchingBlocks or getOpCodes is yet to be
|
598 |
+
* called. The other calculation methods (quickRatio and realquickRatio)
|
599 |
+
* can be used to perform quicker calculations but may be less accurate.
|
600 |
+
*
|
601 |
+
* The ratio is calculated as (2 * number of matches) / total number of
|
602 |
+
* elements in both sequences.
|
603 |
+
*
|
604 |
+
* @return float The calculated ratio.
|
605 |
+
*/
|
606 |
+
public function Ratio()
|
607 |
+
{
|
608 |
+
$matches = array_reduce($this->getMatchingBlocks(), array($this, 'ratioReduce'), 0);
|
609 |
+
return $this->calculateRatio($matches, count ($this->a) + count ($this->b));
|
610 |
+
}
|
611 |
+
|
612 |
+
/**
|
613 |
+
* Helper function to calculate the number of matches for Ratio().
|
614 |
+
*
|
615 |
+
* @param int $sum The running total for the number of matches.
|
616 |
+
* @param array $triple Array containing the matching block triple to add to the running total.
|
617 |
+
* @return int The new running total for the number of matches.
|
618 |
+
*/
|
619 |
+
private function ratioReduce($sum, $triple)
|
620 |
+
{
|
621 |
+
return $sum + ($triple[count($triple) - 1]);
|
622 |
+
}
|
623 |
+
|
624 |
+
/**
|
625 |
+
* Quickly return an upper bound ratio for the similarity of the strings.
|
626 |
+
* This is quicker to compute than Ratio().
|
627 |
+
*
|
628 |
+
* @return float The calculated ratio.
|
629 |
+
*/
|
630 |
+
private function quickRatio()
|
631 |
+
{
|
632 |
+
if($this->fullBCount === null) {
|
633 |
+
$this->fullBCount = array();
|
634 |
+
$bLength = count ($b);
|
635 |
+
for($i = 0; $i < $bLength; ++$i) {
|
636 |
+
$char = $this->b[$i];
|
637 |
+
$this->fullBCount[$char] = $this->arrayGetDefault($this->fullBCount, $char, 0) + 1;
|
638 |
+
}
|
639 |
+
}
|
640 |
+
|
641 |
+
$avail = array();
|
642 |
+
$matches = 0;
|
643 |
+
$aLength = count ($this->a);
|
644 |
+
for($i = 0; $i < $aLength; ++$i) {
|
645 |
+
$char = $this->a[$i];
|
646 |
+
if(isset($avail[$char])) {
|
647 |
+
$numb = $avail[$char];
|
648 |
+
}
|
649 |
+
else {
|
650 |
+
$numb = $this->arrayGetDefault($this->fullBCount, $char, 0);
|
651 |
+
}
|
652 |
+
$avail[$char] = $numb - 1;
|
653 |
+
if($numb > 0) {
|
654 |
+
++$matches;
|
655 |
+
}
|
656 |
+
}
|
657 |
+
|
658 |
+
$this->calculateRatio($matches, count ($this->a) + count ($this->b));
|
659 |
+
}
|
660 |
+
|
661 |
+
/**
|
662 |
+
* Return an upper bound ratio really quickly for the similarity of the strings.
|
663 |
+
* This is quicker to compute than Ratio() and quickRatio().
|
664 |
+
*
|
665 |
+
* @return float The calculated ratio.
|
666 |
+
*/
|
667 |
+
private function realquickRatio()
|
668 |
+
{
|
669 |
+
$aLength = count ($this->a);
|
670 |
+
$bLength = count ($this->b);
|
671 |
+
|
672 |
+
return $this->calculateRatio(min($aLength, $bLength), $aLength + $bLength);
|
673 |
+
}
|
674 |
+
|
675 |
+
/**
|
676 |
+
* Helper function for calculating the ratio to measure similarity for the strings.
|
677 |
+
* The ratio is defined as being 2 * (number of matches / total length)
|
678 |
+
*
|
679 |
+
* @param int $matches The number of matches in the two strings.
|
680 |
+
* @param int $length The length of the two strings.
|
681 |
+
* @return float The calculated ratio.
|
682 |
+
*/
|
683 |
+
private function calculateRatio($matches, $length=0)
|
684 |
+
{
|
685 |
+
if($length) {
|
686 |
+
return 2 * ($matches / $length);
|
687 |
+
}
|
688 |
+
else {
|
689 |
+
return 1;
|
690 |
+
}
|
691 |
+
}
|
692 |
+
|
693 |
+
/**
|
694 |
+
* Helper function that provides the ability to return the value for a key
|
695 |
+
* in an array of it exists, or if it doesn't then return a default value.
|
696 |
+
* Essentially cleaner than doing a series of if(isset()) {} else {} calls.
|
697 |
+
*
|
698 |
+
* @param array $array The array to search.
|
699 |
+
* @param string $key The key to check that exists.
|
700 |
+
* @param mixed $default The value to return as the default value if the key doesn't exist.
|
701 |
+
* @return mixed The value from the array if the key exists or otherwise the default.
|
702 |
+
*/
|
703 |
+
private function arrayGetDefault($array, $key, $default)
|
704 |
+
{
|
705 |
+
if(isset($array[$key])) {
|
706 |
+
return $array[$key];
|
707 |
+
}
|
708 |
+
else {
|
709 |
+
return $default;
|
710 |
+
}
|
711 |
+
}
|
712 |
+
|
713 |
+
/**
|
714 |
+
* Sort an array by the nested arrays it contains. Helper function for getMatchingBlocks
|
715 |
+
*
|
716 |
+
* @param array $a First array to compare.
|
717 |
+
* @param array $b Second array to compare.
|
718 |
+
* @return int -1, 0 or 1, as expected by the usort function.
|
719 |
+
*/
|
720 |
+
private function tupleSort($a, $b)
|
721 |
+
{
|
722 |
+
$max = max(count($a), count($b));
|
723 |
+
for($i = 0; $i < $max; ++$i) {
|
724 |
+
if($a[$i] < $b[$i]) {
|
725 |
+
return -1;
|
726 |
+
}
|
727 |
+
else if($a[$i] > $b[$i]) {
|
728 |
+
return 1;
|
729 |
+
}
|
730 |
+
}
|
731 |
+
|
732 |
+
if(count($a) == $count($b)) {
|
733 |
+
return 0;
|
734 |
+
}
|
735 |
+
else if(count($a) < count($b)) {
|
736 |
+
return -1;
|
737 |
+
}
|
738 |
+
else {
|
739 |
+
return 1;
|
740 |
+
}
|
741 |
+
}
|
742 |
}
|
libs/dumper.php
CHANGED
@@ -5,7 +5,7 @@
|
|
5 |
* (c) 2create Studio, Bulgaria
|
6 |
* http://2create.bg/
|
7 |
*/
|
8 |
-
abstract class
|
9 |
/**
|
10 |
* File Handle
|
11 |
*/
|
@@ -21,16 +21,16 @@ abstract class Shuttle_Dump_File {
|
|
21 |
|
22 |
static function create($filename) {
|
23 |
if (self::is_gzip($filename)) {
|
24 |
-
return new
|
25 |
}
|
26 |
-
return new
|
27 |
}
|
28 |
function __construct($file) {
|
29 |
$this->file_location = $file;
|
30 |
$this->fh = $this->open();
|
31 |
|
32 |
if (!$this->fh) {
|
33 |
-
throw new
|
34 |
}
|
35 |
}
|
36 |
|
@@ -42,7 +42,7 @@ abstract class Shuttle_Dump_File {
|
|
42 |
/**
|
43 |
* Plain text implementation. Uses standard file functions in PHP.
|
44 |
*/
|
45 |
-
class
|
46 |
function open() {
|
47 |
return fopen($this->file_location, 'w');
|
48 |
}
|
@@ -57,7 +57,7 @@ class Shuttle_Dump_File_Plaintext extends Shuttle_Dump_File {
|
|
57 |
/**
|
58 |
* Gzip implementation. Uses gz* functions.
|
59 |
*/
|
60 |
-
class
|
61 |
function open() {
|
62 |
return gzopen($this->file_location, 'wb9');
|
63 |
}
|
@@ -72,7 +72,7 @@ class Shuttle_Dump_File_Gzip extends Shuttle_Dump_File {
|
|
72 |
/**
|
73 |
* MySQL insert statement builder.
|
74 |
*/
|
75 |
-
class
|
76 |
private $rows = array();
|
77 |
private $length = 0;
|
78 |
private $table;
|
@@ -98,7 +98,7 @@ class Shuttle_Insert_Statement {
|
|
98 |
}
|
99 |
|
100 |
return 'INSERT INTO `' . $this->table . '` VALUES ' .
|
101 |
-
implode(",\n", $this->rows) . ';
|
102 |
}
|
103 |
|
104 |
function get_length() {
|
@@ -109,19 +109,19 @@ class Shuttle_Insert_Statement {
|
|
109 |
/**
|
110 |
* Main facade
|
111 |
*/
|
112 |
-
abstract class
|
113 |
/**
|
114 |
* Maximum length of single insert statement
|
115 |
*/
|
116 |
const INSERT_THRESHOLD = 838860;
|
117 |
|
118 |
/**
|
119 |
-
* @var
|
120 |
*/
|
121 |
public $db;
|
122 |
|
123 |
/**
|
124 |
-
* @var
|
125 |
*/
|
126 |
public $dump_file;
|
127 |
|
@@ -144,7 +144,7 @@ abstract class Shuttle_Dumper {
|
|
144 |
* Factory method for dumper on current hosts's configuration.
|
145 |
*/
|
146 |
static function create($db_options) {
|
147 |
-
$db =
|
148 |
|
149 |
$db->connect();
|
150 |
|
@@ -152,9 +152,9 @@ abstract class Shuttle_Dumper {
|
|
152 |
&& self::is_shell_command_available('mysqldump')
|
153 |
&& self::is_shell_command_available('gzip')
|
154 |
) {
|
155 |
-
$dumper = new
|
156 |
} else {
|
157 |
-
$dumper = new
|
158 |
}
|
159 |
|
160 |
if (isset($db_options['include_tables'])) {
|
@@ -167,7 +167,7 @@ abstract class Shuttle_Dumper {
|
|
167 |
return $dumper;
|
168 |
}
|
169 |
|
170 |
-
function __construct(
|
171 |
$this->db = $db;
|
172 |
}
|
173 |
|
@@ -244,7 +244,7 @@ abstract class Shuttle_Dumper {
|
|
244 |
}
|
245 |
}
|
246 |
|
247 |
-
class
|
248 |
function dump($export_file_location, $table_prefix='') {
|
249 |
$command = 'mysqldump -h ' . escapeshellarg($this->db->host) .
|
250 |
' -u ' . escapeshellarg($this->db->username) .
|
@@ -264,7 +264,7 @@ class Shuttle_Dumper_ShellCommand extends Shuttle_Dumper {
|
|
264 |
|
265 |
$command .= ' 2> ' . escapeshellarg($error_file);
|
266 |
|
267 |
-
if (
|
268 |
$command .= ' | gzip';
|
269 |
}
|
270 |
|
@@ -275,19 +275,19 @@ class Shuttle_Dumper_ShellCommand extends Shuttle_Dumper {
|
|
275 |
if ($return_val !== 0) {
|
276 |
$error_text = file_get_contents($error_file);
|
277 |
unlink($error_file);
|
278 |
-
throw new
|
279 |
}
|
280 |
|
281 |
unlink($error_file);
|
282 |
}
|
283 |
}
|
284 |
|
285 |
-
class
|
286 |
public function dump($export_file_location, $table_prefix='') {
|
287 |
global $wp_reset;
|
288 |
$eol = $this->eol;
|
289 |
|
290 |
-
$this->dump_file =
|
291 |
|
292 |
$this->dump_file->write("-- Generation time: " . date('r') . $eol);
|
293 |
$this->dump_file->write("-- Host: " . $this->db->host . $eol);
|
@@ -334,7 +334,7 @@ class Shuttle_Dumper_Native extends Shuttle_Dumper {
|
|
334 |
|
335 |
$data = $this->db->query("SELECT * FROM `$table`");
|
336 |
|
337 |
-
$insert = new
|
338 |
|
339 |
while ($row = $this->db->fetch_row($data)) {
|
340 |
$row_values = array();
|
@@ -364,7 +364,7 @@ class Shuttle_Dumper_Native extends Shuttle_Dumper {
|
|
364 |
}
|
365 |
}
|
366 |
|
367 |
-
class
|
368 |
public $host;
|
369 |
public $username;
|
370 |
public $password;
|
@@ -384,25 +384,25 @@ class Shuttle_DBConn {
|
|
384 |
|
385 |
static function create($options) {
|
386 |
if (class_exists('mysqli')) {
|
387 |
-
$class_name = "
|
388 |
} else {
|
389 |
-
$class_name = "
|
390 |
}
|
391 |
|
392 |
return new $class_name($options);
|
393 |
}
|
394 |
}
|
395 |
|
396 |
-
class
|
397 |
function connect() {
|
398 |
$this->connection = @mysql_connect($this->host, $this->username, $this->password);
|
399 |
if (!$this->connection) {
|
400 |
-
throw new
|
401 |
}
|
402 |
|
403 |
$select_db_res = mysql_select_db($this->name, $this->connection);
|
404 |
if (!$select_db_res) {
|
405 |
-
throw new
|
406 |
}
|
407 |
|
408 |
return true;
|
@@ -414,7 +414,7 @@ class Shuttle_DBConn_Mysql extends Shuttle_DBConn {
|
|
414 |
}
|
415 |
$res = mysql_query($q);
|
416 |
if (!$res) {
|
417 |
-
throw new
|
418 |
}
|
419 |
return $res;
|
420 |
}
|
@@ -455,12 +455,12 @@ class Shuttle_DBConn_Mysql extends Shuttle_DBConn {
|
|
455 |
}
|
456 |
|
457 |
|
458 |
-
class
|
459 |
function connect() {
|
460 |
$this->connection = @new MySQLi($this->host, $this->username, $this->password, $this->name);
|
461 |
|
462 |
if ($this->connection->connect_error) {
|
463 |
-
throw new
|
464 |
}
|
465 |
|
466 |
return true;
|
@@ -473,7 +473,7 @@ class Shuttle_DBConn_Mysqli extends Shuttle_DBConn {
|
|
473 |
$res = $this->connection->query($q);
|
474 |
|
475 |
if (!$res) {
|
476 |
-
throw new
|
477 |
}
|
478 |
|
479 |
return $res;
|
@@ -514,4 +514,4 @@ class Shuttle_DBConn_Mysqli extends Shuttle_DBConn {
|
|
514 |
}
|
515 |
}
|
516 |
|
517 |
-
class
|
5 |
* (c) 2create Studio, Bulgaria
|
6 |
* http://2create.bg/
|
7 |
*/
|
8 |
+
abstract class WPR_Shuttle_Dump_File {
|
9 |
/**
|
10 |
* File Handle
|
11 |
*/
|
21 |
|
22 |
static function create($filename) {
|
23 |
if (self::is_gzip($filename)) {
|
24 |
+
return new WPR_Shuttle_Dump_File_Gzip($filename);
|
25 |
}
|
26 |
+
return new WPR_Shuttle_Dump_File_Plaintext($filename);
|
27 |
}
|
28 |
function __construct($file) {
|
29 |
$this->file_location = $file;
|
30 |
$this->fh = $this->open();
|
31 |
|
32 |
if (!$this->fh) {
|
33 |
+
throw new WPR_Shuttle_Exception("Couldn't write SQL export file");
|
34 |
}
|
35 |
}
|
36 |
|
42 |
/**
|
43 |
* Plain text implementation. Uses standard file functions in PHP.
|
44 |
*/
|
45 |
+
class WPR_Shuttle_Dump_File_Plaintext extends WPR_Shuttle_Dump_File {
|
46 |
function open() {
|
47 |
return fopen($this->file_location, 'w');
|
48 |
}
|
57 |
/**
|
58 |
* Gzip implementation. Uses gz* functions.
|
59 |
*/
|
60 |
+
class WPR_Shuttle_Dump_File_Gzip extends WPR_Shuttle_Dump_File {
|
61 |
function open() {
|
62 |
return gzopen($this->file_location, 'wb9');
|
63 |
}
|
72 |
/**
|
73 |
* MySQL insert statement builder.
|
74 |
*/
|
75 |
+
class WPR_Shuttle_Insert_Statement {
|
76 |
private $rows = array();
|
77 |
private $length = 0;
|
78 |
private $table;
|
98 |
}
|
99 |
|
100 |
return 'INSERT INTO `' . $this->table . '` VALUES ' .
|
101 |
+
implode(",\n", $this->rows) . ';';
|
102 |
}
|
103 |
|
104 |
function get_length() {
|
109 |
/**
|
110 |
* Main facade
|
111 |
*/
|
112 |
+
abstract class WPR_Shuttle_Dumper {
|
113 |
/**
|
114 |
* Maximum length of single insert statement
|
115 |
*/
|
116 |
const INSERT_THRESHOLD = 838860;
|
117 |
|
118 |
/**
|
119 |
+
* @var WPR_Shuttle_DBConn
|
120 |
*/
|
121 |
public $db;
|
122 |
|
123 |
/**
|
124 |
+
* @var WPR_Shuttle_Dump_File
|
125 |
*/
|
126 |
public $dump_file;
|
127 |
|
144 |
* Factory method for dumper on current hosts's configuration.
|
145 |
*/
|
146 |
static function create($db_options) {
|
147 |
+
$db = WPR_Shuttle_DBConn::create($db_options);
|
148 |
|
149 |
$db->connect();
|
150 |
|
152 |
&& self::is_shell_command_available('mysqldump')
|
153 |
&& self::is_shell_command_available('gzip')
|
154 |
) {
|
155 |
+
$dumper = new WPR_Shuttle_Dumper_ShellCommand($db);
|
156 |
} else {
|
157 |
+
$dumper = new WPR_Shuttle_Dumper_Native($db);
|
158 |
}
|
159 |
|
160 |
if (isset($db_options['include_tables'])) {
|
167 |
return $dumper;
|
168 |
}
|
169 |
|
170 |
+
function __construct(WPR_Shuttle_DBConn $db) {
|
171 |
$this->db = $db;
|
172 |
}
|
173 |
|
244 |
}
|
245 |
}
|
246 |
|
247 |
+
class WPR_Shuttle_Dumper_ShellCommand extends WPR_Shuttle_Dumper {
|
248 |
function dump($export_file_location, $table_prefix='') {
|
249 |
$command = 'mysqldump -h ' . escapeshellarg($this->db->host) .
|
250 |
' -u ' . escapeshellarg($this->db->username) .
|
264 |
|
265 |
$command .= ' 2> ' . escapeshellarg($error_file);
|
266 |
|
267 |
+
if (WPR_Shuttle_Dump_File::is_gzip($export_file_location)) {
|
268 |
$command .= ' | gzip';
|
269 |
}
|
270 |
|
275 |
if ($return_val !== 0) {
|
276 |
$error_text = file_get_contents($error_file);
|
277 |
unlink($error_file);
|
278 |
+
throw new WPR_Shuttle_Exception('Couldn\'t export database: ' . $error_text);
|
279 |
}
|
280 |
|
281 |
unlink($error_file);
|
282 |
}
|
283 |
}
|
284 |
|
285 |
+
class WPR_Shuttle_Dumper_Native extends WPR_Shuttle_Dumper {
|
286 |
public function dump($export_file_location, $table_prefix='') {
|
287 |
global $wp_reset;
|
288 |
$eol = $this->eol;
|
289 |
|
290 |
+
$this->dump_file = WPR_Shuttle_Dump_File::create($export_file_location);
|
291 |
|
292 |
$this->dump_file->write("-- Generation time: " . date('r') . $eol);
|
293 |
$this->dump_file->write("-- Host: " . $this->db->host . $eol);
|
334 |
|
335 |
$data = $this->db->query("SELECT * FROM `$table`");
|
336 |
|
337 |
+
$insert = new WPR_Shuttle_Insert_Statement($table);
|
338 |
|
339 |
while ($row = $this->db->fetch_row($data)) {
|
340 |
$row_values = array();
|
364 |
}
|
365 |
}
|
366 |
|
367 |
+
class WPR_Shuttle_DBConn {
|
368 |
public $host;
|
369 |
public $username;
|
370 |
public $password;
|
384 |
|
385 |
static function create($options) {
|
386 |
if (class_exists('mysqli')) {
|
387 |
+
$class_name = "WPR_Shuttle_DBConn_Mysqli";
|
388 |
} else {
|
389 |
+
$class_name = "WPR_Shuttle_DBConn_Mysql";
|
390 |
}
|
391 |
|
392 |
return new $class_name($options);
|
393 |
}
|
394 |
}
|
395 |
|
396 |
+
class WPR_Shuttle_DBConn_Mysql extends WPR_Shuttle_DBConn {
|
397 |
function connect() {
|
398 |
$this->connection = @mysql_connect($this->host, $this->username, $this->password);
|
399 |
if (!$this->connection) {
|
400 |
+
throw new WPR_Shuttle_Exception("Couldn't connect to the database: " . mysql_error());
|
401 |
}
|
402 |
|
403 |
$select_db_res = mysql_select_db($this->name, $this->connection);
|
404 |
if (!$select_db_res) {
|
405 |
+
throw new WPR_Shuttle_Exception("Couldn't select database: " . mysql_error($this->connection));
|
406 |
}
|
407 |
|
408 |
return true;
|
414 |
}
|
415 |
$res = mysql_query($q);
|
416 |
if (!$res) {
|
417 |
+
throw new WPR_Shuttle_Exception("SQL error: " . mysql_error($this->connection));
|
418 |
}
|
419 |
return $res;
|
420 |
}
|
455 |
}
|
456 |
|
457 |
|
458 |
+
class WPR_Shuttle_DBConn_Mysqli extends WPR_Shuttle_DBConn {
|
459 |
function connect() {
|
460 |
$this->connection = @new MySQLi($this->host, $this->username, $this->password, $this->name);
|
461 |
|
462 |
if ($this->connection->connect_error) {
|
463 |
+
throw new WPR_Shuttle_Exception("Couldn't connect to the database: " . $this->connection->connect_error);
|
464 |
}
|
465 |
|
466 |
return true;
|
473 |
$res = $this->connection->query($q);
|
474 |
|
475 |
if (!$res) {
|
476 |
+
throw new WPR_Shuttle_Exception("SQL error: " . $this->connection->error);
|
477 |
}
|
478 |
|
479 |
return $res;
|
514 |
}
|
515 |
}
|
516 |
|
517 |
+
class WPR_Shuttle_Exception extends Exception {};
|
readme.txt
CHANGED
@@ -3,16 +3,16 @@ Tags: wordpress reset, reset database, reset wordpress database, reset, advanced
|
|
3 |
Contributors: WebFactory, wpreset, googlemapswidget, underconstructionpage
|
4 |
Requires at least: 4.0
|
5 |
Requires PHP: 5.2
|
6 |
-
Tested up to: 5.
|
7 |
-
Stable tag: 1.
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
11 |
-
WP Reset resets
|
12 |
|
13 |
== Description ==
|
14 |
|
15 |
-
<a href="https://wpreset.com/?utm_source=wordpressorg&utm_medium=content&utm_campaign=wp-reset&utm_term=wp-reset-top">WP Reset</a> quickly resets the site's database to the default installation values without modifying any files. It deletes all customizations and content, or just chosen parts like theme settings. WP Reset is fast and safe to use thanks to the built-in 1-click
|
16 |
|
17 |
https://youtu.be/qMnkCW2PFoI?rel=0
|
18 |
|
@@ -23,7 +23,7 @@ Access WP Reset admin page via the "Tools" menu.
|
|
23 |
WP Reset is fully integrated with <a href="https://wordpress.org/plugins/wp-webhooks/">WP Webhooks</a> plugin - a secure, universal system that connects WP to any 3rd party systems and enables you to initiate actions both from WordPress (for instance start a MailChimp campaign once a new user registers), and from any other application (create a new user in WP when a purchase is made on a 3rd party system). View more <a href="https://underconstructionpage.com/wp-webhooks-connect-integrate-wordpress/" target="_blank">practical use-cases</a> that save hours of repetitive work.
|
24 |
|
25 |
|
26 |
-
**Please read carefully before proceeding to understand what WP Reset does, and remember to always create a
|
27 |
|
28 |
#### Resetting will delete:
|
29 |
|
@@ -40,20 +40,28 @@ WP Reset is fully integrated with <a href="https://wordpress.org/plugins/wp-webh
|
|
40 |
|
41 |
#### What happens when I click the Reset button?
|
42 |
|
43 |
-
* remember to always
|
44 |
* you will have to confirm the action one more time because there is NO UNDO
|
45 |
* everything will be reset; see bullets above for details
|
46 |
* site title, WordPress address, site address, site language, search engine visibility settings as well as the current user will be restored
|
47 |
* you will be logged out, automatically logged in and taken to the admin dashboard
|
48 |
* WP Reset plugin will be reactivated if that option is chosen in the post-reset options
|
49 |
|
50 |
-
####
|
51 |
|
52 |
-
|
53 |
|
54 |
#### WP-CLI support
|
55 |
|
56 |
-
WP Reset comes with full WP-CLI support. Help on our WP-CLI commands is available via _wp help reset_. By default the commands have to be confirmed but you can use the `--yes` option to skip confirmation. Instead of the active user, the first user with admin privileges found in the database will be restored after reset. Please be careful when using WP Reset with WP-CLI - as with using the GUI
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
|
58 |
#### Database Snapshots
|
59 |
|
@@ -110,6 +118,15 @@ Or if needed, upload manually;
|
|
110 |
|
111 |
== Changelog ==
|
112 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
= v1.70 =
|
114 |
* 2019/09/27
|
115 |
* bug fixes
|
3 |
Contributors: WebFactory, wpreset, googlemapswidget, underconstructionpage
|
4 |
Requires at least: 4.0
|
5 |
Requires PHP: 5.2
|
6 |
+
Tested up to: 5.3
|
7 |
+
Stable tag: 1.75
|
8 |
License: GPLv2 or later
|
9 |
License URI: http://www.gnu.org/licenses/gpl-2.0.html
|
10 |
|
11 |
+
WP Reset resets the whole site, or just the chosen parts, to the default values. It's safe to use with a built-in restore function.
|
12 |
|
13 |
== Description ==
|
14 |
|
15 |
+
<a href="https://wpreset.com/?utm_source=wordpressorg&utm_medium=content&utm_campaign=wp-reset&utm_term=wp-reset-top">WP Reset</a> quickly resets the site's database to the default installation values without modifying any files. It deletes all customizations and content, or just chosen parts like theme settings. WP Reset is fast and safe to use thanks to the built-in snapshots which provide 1-click restore functionality. It has multiple fail-safe mechanisms so you can never accidentally lose data. WP Reset is extremely helpful for plugin and theme developers. It **speeds up testing & debugging** by providing a quick way to reset settings and re-test code. It's the only WP development tool for non-developers.
|
16 |
|
17 |
https://youtu.be/qMnkCW2PFoI?rel=0
|
18 |
|
23 |
WP Reset is fully integrated with <a href="https://wordpress.org/plugins/wp-webhooks/">WP Webhooks</a> plugin - a secure, universal system that connects WP to any 3rd party systems and enables you to initiate actions both from WordPress (for instance start a MailChimp campaign once a new user registers), and from any other application (create a new user in WP when a purchase is made on a 3rd party system). View more <a href="https://underconstructionpage.com/wp-webhooks-connect-integrate-wordpress/" target="_blank">practical use-cases</a> that save hours of repetitive work.
|
24 |
|
25 |
|
26 |
+
**Please read carefully before proceeding to understand what WP Reset does, and remember to always create a snapshot**
|
27 |
|
28 |
#### Resetting will delete:
|
29 |
|
40 |
|
41 |
#### What happens when I click the Reset button?
|
42 |
|
43 |
+
* remember to always create a snapshot first or a full backup
|
44 |
* you will have to confirm the action one more time because there is NO UNDO
|
45 |
* everything will be reset; see bullets above for details
|
46 |
* site title, WordPress address, site address, site language, search engine visibility settings as well as the current user will be restored
|
47 |
* you will be logged out, automatically logged in and taken to the admin dashboard
|
48 |
* WP Reset plugin will be reactivated if that option is chosen in the post-reset options
|
49 |
|
50 |
+
#### Undoing a reset
|
51 |
|
52 |
+
Before doing a reset, create a snapshot. The button is located right next to the reset button and it takes less than 10 seconds to create a snapshot. After reset is done, if you need to undo it simply restore the snapshot and that's it.
|
53 |
|
54 |
#### WP-CLI support
|
55 |
|
56 |
+
WP Reset comes with full WP-CLI support. Help on our WP-CLI commands is available via _wp help reset_. By default the commands have to be confirmed but you can use the `--yes` option to skip confirmation. Instead of the active user, the first user with admin privileges found in the database will be restored after reset. Please be careful when using WP Reset with WP-CLI - as with using the GUI always make a snapshot or backup first.
|
57 |
+
|
58 |
+
Currently supported WP-CLI commands:
|
59 |
+
|
60 |
+
* `wp reset reset`
|
61 |
+
* `wp reset version`
|
62 |
+
* `wp reset delete`
|
63 |
+
* `wp reset snapshots`
|
64 |
+
|
65 |
|
66 |
#### Database Snapshots
|
67 |
|
118 |
|
119 |
== Changelog ==
|
120 |
|
121 |
+
= v1.75 =
|
122 |
+
* 2019/11/12
|
123 |
+
* bug fixes
|
124 |
+
* more GUI improvements
|
125 |
+
* updates for WP v5.3
|
126 |
+
* removed the 1-click backup tool in favor of snapshots - less confusing & same end result
|
127 |
+
* two huge bug fixes thanks to @markwill
|
128 |
+
* 1,241,470 downloads
|
129 |
+
|
130 |
= v1.70 =
|
131 |
* 2019/09/27
|
132 |
* bug fixes
|
wp-reset-cli.php
CHANGED
@@ -321,75 +321,12 @@ class WP_Reset_CLI extends WP_CLI_Command
|
|
321 |
|
322 |
|
323 |
/**
|
324 |
-
*
|
325 |
-
*
|
326 |
-
* ## OPTIONS
|
327 |
-
*
|
328 |
-
* <create|list>
|
329 |
-
* : Actions to take with backup(s).
|
330 |
-
*
|
331 |
-
* ## EXAMPLES
|
332 |
-
*
|
333 |
-
* $ wp reset backup create
|
334 |
-
* Success: New backup created; /wp-content/wp-reset-backups/wp-reset-backup-site-com-2019-09-25-16-44-37-654a.sql.gz
|
335 |
-
*
|
336 |
-
* $ wp reset backup list
|
337 |
-
* Success: 2 backups found.
|
338 |
-
* ---
|
339 |
-
* -
|
340 |
-
* file: /wp-content/wp-reset-backups/wp-reset-backup-site-com-2019-09-24-15-35-55-6514.sql.gz
|
341 |
-
* -
|
342 |
-
* file: /wp-content/wp-reset-backups/wp-reset-backup-site-com-2019-09-24-15-38-09-45ab.sql.gz
|
343 |
-
*
|
344 |
-
* @when after_wp_load
|
345 |
*/
|
346 |
-
function
|
347 |
{
|
348 |
-
|
349 |
-
|
350 |
-
if (empty($args[0])) {
|
351 |
-
WP_CLI::error('Please choose a subcommand: create or list.');
|
352 |
-
return;
|
353 |
-
} elseif (false == in_array($args[0], array('create', 'list'))) {
|
354 |
-
WP_CLI::error('Unknown subcommand. Please choose from: create or list.');
|
355 |
-
} else {
|
356 |
-
$subcommand = $args[0];
|
357 |
-
}
|
358 |
-
|
359 |
-
switch ($subcommand) {
|
360 |
-
case 'create':
|
361 |
-
$filename = $wp_reset->do_create_backup(true);
|
362 |
-
if (is_wp_error($filename)) {
|
363 |
-
WP_CLI::error('Unable to create new backup. ' . $filename->get_error_message());
|
364 |
-
} else {
|
365 |
-
WP_CLI::success('New backup created: /wp-content/' . $wp_reset->backups_folder . '/' . $filename);
|
366 |
-
}
|
367 |
-
break;
|
368 |
-
case 'list':
|
369 |
-
$out = array();
|
370 |
-
$files = @scandir(trailingslashit(WP_CONTENT_DIR) . $wp_reset->backups_folder . '/');
|
371 |
-
if (false === $files || !is_array($files)) {
|
372 |
-
WP_CLI::error('Unable to open backups folder.');
|
373 |
-
} else {
|
374 |
-
foreach ($files as $file) {
|
375 |
-
if (substr($file, -3) == '.gz') {
|
376 |
-
$out[] = array('file' => '/wp-content/' . $wp_reset->backups_folder . '/' . $file);
|
377 |
-
}
|
378 |
-
} // foreach
|
379 |
-
if ($out) {
|
380 |
-
WP_CLI::success(sizeof($out) . ' backup' . (sizeof($out) == 1 ? '' : 's') . ' found.');
|
381 |
-
WP_CLI\Utils\format_items('yaml', $out, array('file'));
|
382 |
-
} else {
|
383 |
-
WP_CLI::error('No backups found.');
|
384 |
-
}
|
385 |
-
}
|
386 |
-
break;
|
387 |
-
default:
|
388 |
-
// should never come to this but can't hurt
|
389 |
-
WP_CLI::error('Unknown subcommand. Please choose from: create or list.');
|
390 |
-
return;
|
391 |
-
}
|
392 |
-
} // backup
|
393 |
} // WP_Reset_CLI
|
394 |
|
395 |
WP_CLI::add_command('reset', 'WP_Reset_CLI');
|
321 |
|
322 |
|
323 |
/**
|
324 |
+
* This command is no longer available. Please use "wp reset snapshots create" instead.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
325 |
*/
|
326 |
+
function backups($args, $assoc_args)
|
327 |
{
|
328 |
+
WP_CLI::error('This command is no longer available. Please use: wp reset snapshots create');
|
329 |
+
} // backups
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
330 |
} // WP_Reset_CLI
|
331 |
|
332 |
WP_CLI::add_command('reset', 'WP_Reset_CLI');
|
wp-reset.php
CHANGED
@@ -2,8 +2,8 @@
|
|
2 |
/*
|
3 |
Plugin Name: WP Reset
|
4 |
Plugin URI: https://wpreset.com/
|
5 |
-
Description: Reset the entire site or selected parts
|
6 |
-
Version: 1.
|
7 |
Author: WebFactory Ltd
|
8 |
Author URI: https://www.webfactoryltd.com/
|
9 |
Text Domain: wp-reset
|
@@ -43,7 +43,6 @@ class WP_Reset
|
|
43 |
public $plugin_url = '';
|
44 |
public $plugin_dir = '';
|
45 |
public $snapshots_folder = 'wp-reset-snapshots-export';
|
46 |
-
public $backups_folder = 'wp-reset-backups';
|
47 |
protected $options = array();
|
48 |
private $delete_count = 0;
|
49 |
private $licensing_servers = array('https://license1.wpreset.com/', 'https://license2.wpreset.com/');
|
@@ -134,14 +133,6 @@ class WP_Reset
|
|
134 |
$options['last_run'] = array();
|
135 |
$change = true;
|
136 |
}
|
137 |
-
if (!isset($options['last_backup_filename'])) {
|
138 |
-
$options['last_backup_filename'] = '';
|
139 |
-
$change = true;
|
140 |
-
}
|
141 |
-
if (!isset($options['last_backup_timestamp'])) {
|
142 |
-
$options['last_backup_timestamp'] = 0;
|
143 |
-
$change = true;
|
144 |
-
}
|
145 |
if (!isset($options['options'])) {
|
146 |
$options['options'] = array();
|
147 |
$change = true;
|
@@ -341,15 +332,12 @@ class WP_Reset
|
|
341 |
'cancel_button' => __('Cancel', 'wp-reset'),
|
342 |
'open_survey' => $survey,
|
343 |
'ok_button' => __('OK', 'wp-reset'),
|
344 |
-
'creating_backup' => __('Creating backup. Please wait.', 'wp-reset'),
|
345 |
'confirm_button' => __('Reset WordPress', 'wp-reset'),
|
346 |
'confirm_title' => __('Are you sure you want to proceed?', 'wp-reset'),
|
347 |
'confirm_title_reset' => __('Are you sure you want to reset the site?', 'wp-reset'),
|
348 |
-
'confirm1' => __('Clicking "Reset WordPress" will reset your site to default values. All content will be lost.
|
349 |
'confirm2' => __('Click "Cancel" to abort.', 'wp-reset'),
|
350 |
'doing_reset' => __('Resetting in progress. Please wait.', 'wp-reset'),
|
351 |
-
'backup_not_accessible' => __('Backup was created but it\'s not accessible.', 'wp-reset'),
|
352 |
-
'backup_not_accessible_details' => __('Please check your folder access rights. File should be accessible on <a href="%url%" target="_blank">this URL</a>.', 'wp-reset'),
|
353 |
'nonce_dismiss_notice' => wp_create_nonce('wp-reset_dismiss_notice'),
|
354 |
'nonce_run_tool' => wp_create_nonce('wp-reset_run_tool'),
|
355 |
'nonce_do_reset' => wp_create_nonce('wp-reset_do_reset'),
|
@@ -960,14 +948,6 @@ class WP_Reset
|
|
960 |
$url = content_url() . '/' . $this->snapshots_folder . '/' . $res;
|
961 |
wp_send_json_success($url);
|
962 |
}
|
963 |
-
} elseif ($tool == 'download_backup') {
|
964 |
-
$res = $this->do_create_backup();
|
965 |
-
if (is_wp_error($res)) {
|
966 |
-
wp_send_json_error($res->get_error_message());
|
967 |
-
} else {
|
968 |
-
$url = content_url() . '/' . $this->backups_folder . '/' . $res;
|
969 |
-
wp_send_json_success($url);
|
970 |
-
}
|
971 |
} elseif ($tool == 'restore_snapshot') {
|
972 |
$res = $this->do_restore_snapshot($extra_data);
|
973 |
if (is_wp_error($res)) {
|
@@ -1266,17 +1246,87 @@ class WP_Reset
|
|
1266 |
|
1267 |
|
1268 |
/**
|
1269 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1270 |
*
|
1271 |
* @return string
|
1272 |
*/
|
1273 |
-
function
|
1274 |
{
|
1275 |
$out = '';
|
1276 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1277 |
|
1278 |
return $out;
|
1279 |
-
} //
|
1280 |
|
1281 |
|
1282 |
/**
|
@@ -1297,19 +1347,20 @@ class WP_Reset
|
|
1297 |
echo '<header>';
|
1298 |
echo '<div class="wpr-container">';
|
1299 |
echo '<img id="logo-icon" src="' . $this->plugin_url . 'img/wp-reset-logo.png" title="' . __('WP Reset', 'wp-reset') . '" alt="' . __('WP Reset', 'wp-reset') . '">';
|
1300 |
-
echo '<a href="' . $this->generate_web_link('header', '/pro-version-launch/') . '" target="_blank" class="button button-primary alignright">Grab the limited LTD offer!</a>';
|
1301 |
echo '</div>';
|
1302 |
echo '</header>';
|
1303 |
|
1304 |
-
echo '<div id="
|
|
|
|
|
1305 |
|
1306 |
echo '<nav>';
|
1307 |
echo '<div class="wpr-container">';
|
1308 |
echo '<ul class="wpr-main-tab">';
|
1309 |
echo '<li><a href="#tab-reset">' . __('Reset', 'wp-reset') . '</a></li>';
|
1310 |
echo '<li><a href="#tab-tools">' . __('Tools', 'wp-reset') . '</a></li>';
|
1311 |
-
echo '<li><a href="#tab-snapshots">' . __('
|
1312 |
-
echo '<li><a href="#tab-collections">' . __('
|
1313 |
echo '<li><a href="#tab-support">' . __('Support', 'wp-reset') . '</a></li>';
|
1314 |
echo '</ul>';
|
1315 |
echo '</div>'; // container
|
@@ -1361,7 +1412,7 @@ class WP_Reset
|
|
1361 |
$questions[] = '<div class="question-wrapper" data-value="backup" title="Click to select/unselect answer">' .
|
1362 |
'<span class="dashicons dashicons-yes"></span>' .
|
1363 |
'<div class="question"><b>Off-site backups</b><br>' .
|
1364 |
-
'<i>Backup the site to Dropbox, FTP or Google Drive before
|
1365 |
'</div>';
|
1366 |
|
1367 |
$questions[] = '<div class="question-wrapper" data-value="wpmu" title="Click to select/unselect answer">' .
|
@@ -1452,7 +1503,7 @@ class WP_Reset
|
|
1452 |
}
|
1453 |
|
1454 |
// ask for review
|
1455 |
-
if ((!empty($meta['reset_count']) || !empty($snapshots) || current_time('timestamp', true) - $meta['first_install'] >
|
1456 |
&& false === $notice_shown
|
1457 |
&& false == $this->get_dismissed_notices('rate')
|
1458 |
) {
|
@@ -1477,15 +1528,16 @@ class WP_Reset
|
|
1477 |
|
1478 |
echo '<div class="card" id="card-description">';
|
1479 |
echo '<h4>';
|
1480 |
-
echo __('Please read carefully before proceeding
|
1481 |
echo '<div class="card-header-right"><a class="toggle-card" href="#" title="' . __('Collapse / expand box', 'wp-reset') . '"><span class="dashicons dashicons-arrow-up-alt2"></span></a></div>';
|
1482 |
echo '</h4>';
|
|
|
1483 |
echo '<p><b class="red">' . __('Resetting will delete:', 'wp-reset') . '</b></p>';
|
1484 |
echo '<ul class="plain-list">';
|
1485 |
echo '<li>' . __('all posts, pages, custom post types, comments, media entries, users', 'wp-reset') . '</li>';
|
1486 |
echo '<li>' . __('all default WP database tables', 'wp-reset') . '</li>';
|
1487 |
echo '<li>' . sprintf(__('all custom database tables that have the same prefix "%s" as default tables in this installation', 'wp-reset'), $wpdb->prefix) . '</li>';
|
1488 |
-
echo '<li>' . __('always <a href="#" class="
|
1489 |
echo '</ul>';
|
1490 |
|
1491 |
echo '<p><b class="green">' . __('Resetting will not delete:', 'wp-reset') . '</b></p>';
|
@@ -1500,8 +1552,8 @@ class WP_Reset
|
|
1500 |
|
1501 |
echo '<p><b>' . __('What happens when I click the Reset button?', 'wp-reset') . '</b></p>';
|
1502 |
echo '<ul class="plain-list">';
|
1503 |
-
echo '<li>' . __('remember, always <a href="#" class="
|
1504 |
-
echo '<li>' . __('you will have to confirm the action one more time
|
1505 |
echo '<li>' . __('everything will be reset; see bullets above for details', 'wp-reset') . '</li>';
|
1506 |
echo '<li>' . __('site title, WordPress address, site address, site language, search engine visibility and current user will be restored', 'wp-reset') . '</li>';
|
1507 |
echo '<li>' . __('you will be logged out, automatically logged in and taken to the admin dashboard', 'wp-reset') . '</li>';
|
@@ -1519,12 +1571,15 @@ class WP_Reset
|
|
1519 |
} else {
|
1520 |
echo '<a href="#" class="open-webhooks-dialog">Install WP Webhooks & WPR addon</a> to automate your workflow, develop faster and connect WordPress to any web app or 3rd party system.';
|
1521 |
}
|
1522 |
-
echo '</p></div>'; // card description
|
1523 |
|
1524 |
$theme = wp_get_theme();
|
1525 |
|
1526 |
echo '<div class="card" id="card-reset">';
|
1527 |
-
echo '<h4>' . __('Reset', 'wp-reset')
|
|
|
|
|
|
|
1528 |
echo '<p><label for="reactivate-theme"><input name="wpr-post-reset[reactivate_theme]" type="checkbox" id="reactivate-theme" value="1"> ' . __('Reactivate current theme', 'wp-reset') . ' - ' . $theme->get('Name') . '</label></p>';
|
1529 |
echo '<p><label for="reactivate-wpreset"><input name="wpr-post-reset[reactivate_wpreset]" type="checkbox" id="reactivate-wpreset" value="1" checked> ' . __('Reactivate WP Reset plugin', 'wp-reset') . '</label></p>';
|
1530 |
if ($this->is_webhooks_active()) {
|
@@ -1536,11 +1591,12 @@ class WP_Reset
|
|
1536 |
} else {
|
1537 |
echo '<p>To run additional actions after reset or automate a complex workflow <a href="#" class="open-webhooks-dialog">install WP Webhooks & WPR addon</a>. It\'s a standard, platform-independent way of connecting WordPress to any web app. This <a href="https://www.youtube.com/watch?v=m8XDFXCNP9g" target="_blank">short video</a> explains it well.</p>';
|
1538 |
}
|
1539 |
-
echo '<p><br>' . __('Type <b>reset</b> in the confirmation field to confirm the reset and then click the "Reset WordPress" button.<br
|
1540 |
|
1541 |
wp_nonce_field('wp-reset');
|
1542 |
echo '<p><input id="wp_reset_confirm" type="text" name="wp_reset_confirm" placeholder="' . esc_attr__('Type in "reset"', 'wp-reset') . '" value="" autocomplete="off"> ';
|
1543 |
-
echo '<a id="wp_reset_submit" class="button button-delete">' . __('Reset
|
|
|
1544 |
echo '</div>';
|
1545 |
} // tab_reset
|
1546 |
|
@@ -1552,51 +1608,111 @@ class WP_Reset
|
|
1552 |
*/
|
1553 |
private function tab_tools()
|
1554 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1555 |
echo '<div class="card">';
|
1556 |
-
echo
|
1557 |
-
echo '<
|
1558 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1559 |
echo '</div>';
|
1560 |
|
1561 |
$upload_dir = wp_upload_dir(date('Y/m'), true);
|
1562 |
$upload_dir['basedir'] = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $upload_dir['basedir']);
|
1563 |
|
1564 |
echo '<div class="card">';
|
1565 |
-
echo
|
|
|
1566 |
echo '<p>' . __('All files in <code>' . $upload_dir['basedir'] . '</code> folder will be deleted. Including folders and subfolders, and files in subfolders. Files associated with <a href="' . admin_url('upload.php') . '">media</a> entries will be deleted too.<br><b>There is NO UNDO. WP Reset does not make any file backups.</b>', 'wp-reset') . '</p>';
|
|
|
|
|
|
|
1567 |
if (false != $upload_dir['error']) {
|
1568 |
-
echo '<p><span style="color:#dd3036;"><b>Tool is not available.</b></span> Folder is not writeable by WordPress. Please check file and folder access rights.</p>';
|
1569 |
} else {
|
1570 |
-
echo '<p><a data-confirm-title="Are you sure you want to delete all files & folders in uploads folder?" data-btn-confirm="Delete everything in uploads folder" data-text-wait="Deleting uploads. Please wait." data-text-confirm="All files and folders in uploads will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="%n files & folders have been deleted." data-text-done-singular="One file or folder has been deleted." class="button button-delete" href="#" id="delete-uploads">Delete all files & folders in uploads folder</a></p>';
|
1571 |
}
|
1572 |
echo '</div>';
|
|
|
1573 |
|
1574 |
echo '<div class="card">';
|
1575 |
-
echo
|
1576 |
-
echo '<
|
1577 |
-
echo '<p
|
|
|
|
|
|
|
1578 |
echo '</div>';
|
1579 |
|
1580 |
$theme = wp_get_theme();
|
1581 |
|
1582 |
echo '<div class="card">';
|
1583 |
-
echo
|
|
|
1584 |
echo '<p>' . __('All themes will be deleted. Including the currently active theme - ' . $theme->get('Name') . '.<br><b>There is NO UNDO. WP Reset does not make any file backups.</b>', 'wp-reset') . '</p>';
|
1585 |
-
|
|
|
|
|
|
|
|
|
1586 |
echo '</div>';
|
1587 |
|
1588 |
echo '<div class="card">';
|
1589 |
-
echo
|
|
|
1590 |
echo '<p>' . __('All plugins will be deleted except for WP Reset which will remain active.<br><b>There is NO UNDO. WP Reset does not make any file backups.</b>', 'wp-reset') . '</p>';
|
1591 |
-
|
|
|
|
|
|
|
|
|
1592 |
echo '</div>';
|
1593 |
|
1594 |
-
global $wpdb;
|
1595 |
$custom_tables = $this->get_custom_tables();
|
1596 |
|
1597 |
echo '<div class="card">';
|
1598 |
-
echo
|
1599 |
-
echo '<
|
|
|
1600 |
if ($custom_tables) {
|
1601 |
echo '<p>' . __('The following ' . sizeof($custom_tables) . ' custom tables are affected by this tool: ');
|
1602 |
foreach ($custom_tables as $tbl) {
|
@@ -1611,19 +1727,26 @@ class WP_Reset
|
|
1611 |
echo '<p>' . __('There are no custom tables. There\'s nothing for this tool to empty or delete.', 'wp-reset') . '</p>';
|
1612 |
$custom_tables_btns = ' disabled';
|
1613 |
}
|
1614 |
-
echo '<p><a data-confirm-title="Are you sure you want to empty all custom tables?" data-btn-confirm="Empty custom tables" data-text-wait="Emptying custom tables. Please wait." data-text-confirm="All custom tables with prefix <code>' . $wpdb->prefix . '</code> will be emptied. There is NO UNDO. Always ' . esc_attr('<a href="#" class="download-backup">create a backup</a>') . '." data-text-done="%n custom tables have been emptied." data-text-done-singular="One custom table has been emptied." class="button button-delete' . $custom_tables_btns . '" href="#" id="truncate-custom-tables">Empty (truncate) custom tables</a>';
|
1615 |
-
echo '<a data-confirm-title="Are you sure you want to delete all custom tables?" data-btn-confirm="Delete custom tables" data-text-wait="Deleting custom tables. Please wait." data-text-confirm="All custom tables with prefix <code>' . $wpdb->prefix . '</code> will be deleted. There is NO UNDO. Always ' . esc_attr('<a href="#" class="download-backup">create a backup</a>') . '." data-text-done="%n custom tables have been deleted." data-text-done-singular="One custom table has been deleted." class="button button-delete' . $custom_tables_btns . '" href="#" id="drop-custom-tables">Delete (drop) custom tables</a>' . $this->get_backup_button('drop-custom-tables') . '</p>';
|
1616 |
|
|
|
|
|
|
|
|
|
|
|
1617 |
echo '</div>';
|
1618 |
|
1619 |
echo '<div class="card">';
|
1620 |
-
echo
|
|
|
1621 |
echo '<p>' . __('This action deletes the .htaccess file located in <code>' . $this->get_htaccess_path() . '</code><br><b>There is NO UNDO. WP Reset does not make any file backups.</b></p>', 'wp-reset');
|
1622 |
|
1623 |
echo '<p>If you need to edit .htaccess, install our free <a href="' . admin_url('plugin-install.php?tab=plugin-information&plugin=wp-htaccess-editor&TB_iframe=true&width=600&height=550') . '" class="thickbox open-plugin-details-modal">WP Htaccess Editor</a> plugin. It automatically creates backups when you edit .htaccess as well as checks for syntax errors. To create the default .htaccess file open <a href="' . admin_url('options-permalink.php') . '">Settings - Permalinks</a> and re-save settings. WordPress will recreate the file.</p>';
|
1624 |
|
1625 |
-
echo
|
1626 |
|
|
|
|
|
|
|
1627 |
echo '</div>';
|
1628 |
} // tab_tools
|
1629 |
|
@@ -1638,7 +1761,7 @@ class WP_Reset
|
|
1638 |
echo '<div class="card">';
|
1639 |
echo '<h4>' . __('What are Plugin & Theme Collections?', 'wp-reset') . '</h4>';
|
1640 |
echo '<p>' . __('A tool that\'s coming with WP Reset PRO that will <b>save hours & hours of your precious time</b>! Have a set of plugins (and themes) that you install and activate after every reset? Or on every fresh WP installation? Well, no more clicking install & active for ten minutes! Build the collection once and install it with one click as many times as needed.<br>WP Reset stores collections in the cloud so they\'re accessible on every site you build. You can use free plugins and themes from the official repo, and PRO ones by uploading a ZIP file. We\'ll safely store your license keys too, so you have everything in one place.', 'wp-reset') . '</p>';
|
1641 |
-
echo '<p
|
1642 |
echo '</div>';
|
1643 |
} // tab_collections
|
1644 |
|
@@ -1660,11 +1783,6 @@ class WP_Reset
|
|
1660 |
echo '<p>' . __('We are very active on the <a href="https://wordpress.org/support/plugin/wp-reset" target="_blank">official WP Reset support forum</a>. If you found a bug, have a feature idea or just want to say hi - please drop by. We love to hear back from our users.', 'wp-reset') . '</p>';
|
1661 |
echo '</div>';
|
1662 |
|
1663 |
-
echo '<div class="card">';
|
1664 |
-
echo '<h4>' . __('Private contact', 'wp-reset') . '</h4>';
|
1665 |
-
echo '<p>' . __('If there\'s a need to contact us privately send emails to <a href="mailto:wpreset@webfactoryltd.com">wpreset@webfactoryltd.com</a>. Please know that although we\'ll gladly have a look at issues you are having with any site, we can\'t promise we\'ll fix them. Thank you for understanding.', 'wp-reset') . '</p>';
|
1666 |
-
echo '</div>';
|
1667 |
-
|
1668 |
echo '<div class="card">';
|
1669 |
echo '<h4>' . __('Care to help out?', 'wp-reset') . '</h4>';
|
1670 |
echo '<p>' . __('No need for donations or anything like that :) If you can give us a <a href="https://wordpress.org/support/plugin/wp-reset/reviews/#new-post" target="_blank">five star rating</a> you\'ll help out more than you can imagine. A public mention <a href="https://twitter.com/webfactoryltd" target="_blank">@webfactoryltd</a> also does wonders. Thank you!', 'wp-reset') . '</p>';
|
@@ -1684,11 +1802,12 @@ class WP_Reset
|
|
1684 |
|
1685 |
echo '<div class="card" id="card-snapshots">';
|
1686 |
echo '<h4>';
|
1687 |
-
echo __('
|
1688 |
echo '<div class="card-header-right"><a class="toggle-card" href="#" title="' . __('Collapse / expand box', 'wp-reset') . '"><span class="dashicons dashicons-arrow-up-alt2"></span></a></div>';
|
1689 |
echo '</h4>';
|
|
|
1690 |
echo '<p>A snapshot is a copy of all WP database tables, standard and custom ones, saved in your database. Files are not saved or included in snapshots in any way. <a href="https://www.youtube.com/watch?v=xBfMmS12vMY" target="_blank">Watch a short video</a> overview and tutorial about Snapshots.</p>';
|
1691 |
-
echo '<p>Snapshots are primarily a development tool.
|
1692 |
echo '<p>Use snapshots to find out what changes a plugin made to your database or to quickly restore the dev environment after testing database related changes. Restoring a snapshot does not affect other snapshots, or WP Reset settings.</p>';
|
1693 |
|
1694 |
$table_status = $wpdb->get_results('SHOW TABLE STATUS');
|
@@ -1721,26 +1840,40 @@ class WP_Reset
|
|
1721 |
|
1722 |
echo '';
|
1723 |
echo '</div>';
|
|
|
1724 |
|
1725 |
-
echo '<div class="card
|
1726 |
echo '<h4>';
|
1727 |
-
echo __('
|
1728 |
-
echo '<div class="card-header-right"><a id="create-new-snapshot-primary" data-msg-success="Snapshot created!" data-msg-wait="Creating snapshot. Please wait." data-btn-confirm="Create snapshot" data-placeholder="Snapshot name or brief description, ie: before plugin install" data-text="Enter snapshot name or brief description, up to 64 characters." data-title="Create a new snapshot" title="Create a new database snapshot" href="#" class="button button-primary create-new-snapshot">' . __('Create
|
1729 |
echo '</h4>';
|
1730 |
|
1731 |
if ($snapshots = $this->get_snapshots()) {
|
|
|
1732 |
echo '<table id="wpr-snapshots">';
|
1733 |
-
echo '<tr><th>
|
1734 |
foreach ($snapshots as $ss) {
|
1735 |
echo '<tr id="wpr-ss-' . $ss['uid'] . '">';
|
1736 |
if (!empty($ss['name'])) {
|
1737 |
-
echo '<td title="Created on ' . date(get_option('date_format'), strtotime($ss['timestamp'])) . ' @ ' . date(get_option('time_format'), strtotime($ss['timestamp'])) . '">' . $ss['name'] . '</td>';
|
1738 |
$name = $ss['name'];
|
1739 |
} else {
|
1740 |
-
echo '<td title="Created on ' . date(get_option('date_format'), strtotime($ss['timestamp'])) . ' @ ' . date(get_option('time_format'), strtotime($ss['timestamp'])) . '">' . '' . date(get_option('date_format'), strtotime($ss['timestamp'])) . '<br>@ ' . date(get_option('time_format'), strtotime($ss['timestamp'])) . '</td>';
|
1741 |
$name = 'created on ' . date(get_option('date_format'), strtotime($ss['timestamp'])) . ' @ ' . date(get_option('time_format'), strtotime($ss['timestamp']));
|
1742 |
}
|
1743 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1744 |
if ($ss['tbl_custom']) {
|
1745 |
echo $ss['tbl_custom'] . ' custom table' . ($ss['tbl_custom'] == 1 ? '' : 's');
|
1746 |
} else {
|
@@ -1748,10 +1881,13 @@ class WP_Reset
|
|
1748 |
}
|
1749 |
echo ' totaling ' . $this->format_size($ss['tbl_size']) . ' in ' . number_format($ss['tbl_rows']) . ' rows</td>';
|
1750 |
echo '<td>';
|
1751 |
-
echo '<
|
1752 |
-
|
1753 |
-
|
1754 |
-
echo '<a data-
|
|
|
|
|
|
|
1755 |
echo '</tr>';
|
1756 |
} // foreach
|
1757 |
echo '</table>';
|
@@ -1986,7 +2122,7 @@ class WP_Reset
|
|
1986 |
require_once $this->plugin_dir . 'libs/dumper.php';
|
1987 |
|
1988 |
try {
|
1989 |
-
$world_dumper =
|
1990 |
'host' => DB_HOST,
|
1991 |
'username' => DB_USER,
|
1992 |
'password' => DB_PASSWORD,
|
@@ -2017,68 +2153,6 @@ class WP_Reset
|
|
2017 |
} // export_snapshot
|
2018 |
|
2019 |
|
2020 |
-
|
2021 |
-
/**
|
2022 |
-
* Exports DB tables as SQL dump; saved in gzipped file in WP_CONTENT folder.
|
2023 |
-
*
|
2024 |
-
* @return string|WP_Error Export base filename, or error object on fail.
|
2025 |
-
*/
|
2026 |
-
function do_create_backup($skip_timestamp_check = false)
|
2027 |
-
{
|
2028 |
-
require_once $this->plugin_dir . 'libs/dumper.php';
|
2029 |
-
global $wpdb;
|
2030 |
-
|
2031 |
-
if (
|
2032 |
-
false == $skip_timestamp_check
|
2033 |
-
&& !empty($this->options['last_backup_timestamp'])
|
2034 |
-
&& !empty($this->options['last_backup_filename'])
|
2035 |
-
&& time() - $this->options['last_backup_timestamp'] < 30
|
2036 |
-
) {
|
2037 |
-
return $this->options['last_backup_filename'];
|
2038 |
-
}
|
2039 |
-
|
2040 |
-
try {
|
2041 |
-
$world_dumper = Shuttle_Dumper::create(array(
|
2042 |
-
'host' => DB_HOST,
|
2043 |
-
'username' => DB_USER,
|
2044 |
-
'password' => DB_PASSWORD,
|
2045 |
-
'db_name' => DB_NAME,
|
2046 |
-
));
|
2047 |
-
|
2048 |
-
$folder = wp_mkdir_p(trailingslashit(WP_CONTENT_DIR) . $this->backups_folder);
|
2049 |
-
if (!$folder) {
|
2050 |
-
return new WP_Error(1, 'Unable to create wp-content/' . $this->backups_folder . '/ folder.');
|
2051 |
-
}
|
2052 |
-
|
2053 |
-
$htaccess_content = 'AddType application/octet-stream .gz' . PHP_EOL;
|
2054 |
-
$htaccess_content .= 'Options -Indexes' . PHP_EOL;
|
2055 |
-
$htaccess_file = @fopen(trailingslashit(WP_CONTENT_DIR) . $this->backups_folder . '/.htaccess', 'w');
|
2056 |
-
if ($htaccess_file) {
|
2057 |
-
fputs($htaccess_file, $htaccess_content);
|
2058 |
-
fclose($htaccess_file);
|
2059 |
-
}
|
2060 |
-
|
2061 |
-
$rand_id = sprintf('%04x', mt_rand(0, 0xFFFF));
|
2062 |
-
$filename = '';
|
2063 |
-
$filename .= 'wp-reset-backup-' . str_replace(array('http://', 'https://', '.'), array('', '', '-'), home_url());
|
2064 |
-
$filename .= '-' . date('Y-m-d-H-i-s', current_time('timestamp')) . '-' . $rand_id;
|
2065 |
-
$filename = sanitize_file_name($filename) . '.sql.gz';
|
2066 |
-
$filename = apply_filters('wp_reset_backup_filename', $filename);
|
2067 |
-
|
2068 |
-
$world_dumper->dump(trailingslashit(WP_CONTENT_DIR) . $this->backups_folder . '/' . $filename, $wpdb->prefix);
|
2069 |
-
} catch (Shuttle_Exception $e) {
|
2070 |
-
return new WP_Error(1, 'Couldn\'t create backup: ' . $e->getMessage());
|
2071 |
-
}
|
2072 |
-
|
2073 |
-
do_action('wp_reset_create_backup', $filename);
|
2074 |
-
|
2075 |
-
$this->update_options('last_backup_timestamp', time());
|
2076 |
-
$this->update_options('last_backup_filename', $filename);
|
2077 |
-
|
2078 |
-
return $filename;
|
2079 |
-
} // create_backup
|
2080 |
-
|
2081 |
-
|
2082 |
/**
|
2083 |
* Replace current tables with ones in snapshot.
|
2084 |
*
|
@@ -2314,8 +2388,8 @@ class WP_Reset
|
|
2314 |
} elseif ($schema1 != $schema2) {
|
2315 |
require_once $this->plugin_dir . 'libs/diff.php';
|
2316 |
require_once $this->plugin_dir . 'libs/diff/Renderer/Html/SideBySide.php';
|
2317 |
-
$diff = new
|
2318 |
-
$renderer = new
|
2319 |
|
2320 |
$out2 .= '<div class="wpr-table-container" data-table="' . $tbl_current['basename'] . '">';
|
2321 |
$out2 .= '<table>';
|
@@ -2476,7 +2550,7 @@ class WP_Reset
|
|
2476 |
}
|
2477 |
}
|
2478 |
|
2479 |
-
if ($plugin_info) {
|
2480 |
array_unshift($res->plugins, $plugin_info);
|
2481 |
}
|
2482 |
|
@@ -2497,7 +2571,6 @@ class WP_Reset
|
|
2497 |
$res = $this->add_plugin_featured('wp-force-ssl', $res);
|
2498 |
$res = $this->add_plugin_featured('eps-301-redirects', $res);
|
2499 |
|
2500 |
-
|
2501 |
return $res;
|
2502 |
} // plugins_api_result
|
2503 |
|
2 |
/*
|
3 |
Plugin Name: WP Reset
|
4 |
Plugin URI: https://wpreset.com/
|
5 |
+
Description: Reset the entire site or just selected parts while reserving the option to undo by using snapshots.
|
6 |
+
Version: 1.75
|
7 |
Author: WebFactory Ltd
|
8 |
Author URI: https://www.webfactoryltd.com/
|
9 |
Text Domain: wp-reset
|
43 |
public $plugin_url = '';
|
44 |
public $plugin_dir = '';
|
45 |
public $snapshots_folder = 'wp-reset-snapshots-export';
|
|
|
46 |
protected $options = array();
|
47 |
private $delete_count = 0;
|
48 |
private $licensing_servers = array('https://license1.wpreset.com/', 'https://license2.wpreset.com/');
|
133 |
$options['last_run'] = array();
|
134 |
$change = true;
|
135 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
136 |
if (!isset($options['options'])) {
|
137 |
$options['options'] = array();
|
138 |
$change = true;
|
332 |
'cancel_button' => __('Cancel', 'wp-reset'),
|
333 |
'open_survey' => $survey,
|
334 |
'ok_button' => __('OK', 'wp-reset'),
|
|
|
335 |
'confirm_button' => __('Reset WordPress', 'wp-reset'),
|
336 |
'confirm_title' => __('Are you sure you want to proceed?', 'wp-reset'),
|
337 |
'confirm_title_reset' => __('Are you sure you want to reset the site?', 'wp-reset'),
|
338 |
+
'confirm1' => __('Clicking "Reset WordPress" will reset your site to default values. All content will be lost. Always <a href="#" class="create-new-snapshot" data-description="Before resetting the site">create a snapshot</a> if you want to be able to undo.</b>', 'wp-reset'),
|
339 |
'confirm2' => __('Click "Cancel" to abort.', 'wp-reset'),
|
340 |
'doing_reset' => __('Resetting in progress. Please wait.', 'wp-reset'),
|
|
|
|
|
341 |
'nonce_dismiss_notice' => wp_create_nonce('wp-reset_dismiss_notice'),
|
342 |
'nonce_run_tool' => wp_create_nonce('wp-reset_run_tool'),
|
343 |
'nonce_do_reset' => wp_create_nonce('wp-reset_do_reset'),
|
948 |
$url = content_url() . '/' . $this->snapshots_folder . '/' . $res;
|
949 |
wp_send_json_success($url);
|
950 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
951 |
} elseif ($tool == 'restore_snapshot') {
|
952 |
$res = $this->do_restore_snapshot($extra_data);
|
953 |
if (is_wp_error($res)) {
|
1246 |
|
1247 |
|
1248 |
/**
|
1249 |
+
* Generate a button that initiates snapshot creation
|
1250 |
+
*
|
1251 |
+
* @param string $tool_id Tool ID.
|
1252 |
+
* @param string $description Snapshot description.
|
1253 |
+
*
|
1254 |
+
* @return string
|
1255 |
+
*/
|
1256 |
+
function get_snapshot_button($tool_id = '', $description = '')
|
1257 |
+
{
|
1258 |
+
$out = '';
|
1259 |
+
$out .= '<a data-tool-id="' . $tool_id . '" data-description="' . esc_attr($description) . '" class="button create-new-snapshot" href="#">Create snapshot</a>';
|
1260 |
+
|
1261 |
+
return $out;
|
1262 |
+
} // get_snapshot_button
|
1263 |
+
|
1264 |
+
|
1265 |
+
/**
|
1266 |
+
* Generate card header including title and action buttons
|
1267 |
+
*
|
1268 |
+
* @param string $title Card title.
|
1269 |
+
* @param string $card_id Card ID.
|
1270 |
+
* @param bool $collapse_button Show collapse button.
|
1271 |
+
* @param bool $iot_button Show index of tools button.
|
1272 |
+
*
|
1273 |
+
* @return string
|
1274 |
+
*/
|
1275 |
+
function get_card_header($title, $card_id, $collapse_button = false, $iot_button = false)
|
1276 |
+
{
|
1277 |
+
$out = '';
|
1278 |
+
$out .= '<h4 id="' . $card_id . '">' . $title;
|
1279 |
+
$out .= '<div class="card-header-right">';
|
1280 |
+
if ($iot_button) {
|
1281 |
+
$out .= '<a class="scrollto" href="#iot" title="Jump to Index of Tools"><span class="dashicons dashicons-screenoptions"></span></a>';
|
1282 |
+
}
|
1283 |
+
if ($collapse_button) {
|
1284 |
+
$out .= '<a class="toggle-card" href="#" title="' . __('Collapse / expand box', 'wp-reset') . '"><span class="dashicons dashicons-arrow-up-alt2"></span></a>';
|
1285 |
+
}
|
1286 |
+
$out .= '</div></h4>';
|
1287 |
+
|
1288 |
+
return $out;
|
1289 |
+
} // get_card_header
|
1290 |
+
|
1291 |
+
|
1292 |
+
/**
|
1293 |
+
* Generate tool icons and description detailing what it modifies
|
1294 |
+
*
|
1295 |
+
* @param bool $modify_files Does the tool modify files?
|
1296 |
+
* @param bool $modify_db Does the tool modify the database?
|
1297 |
+
* @param bool $plural Is there more than one tool in the set?
|
1298 |
*
|
1299 |
* @return string
|
1300 |
*/
|
1301 |
+
function get_tool_icons($modify_files = false, $modify_db = false, $plural = false)
|
1302 |
{
|
1303 |
$out = '';
|
1304 |
+
|
1305 |
+
$out .= '<p class="tool-icons">';
|
1306 |
+
$out .= '<i class="icon-doc-text-inv' . ($modify_files ? ' red' : '') . '"></i> ';
|
1307 |
+
$out .= '<i class="icon-database' . ($modify_db ? ' red' : '') . '"></i> ';
|
1308 |
+
|
1309 |
+
if ($plural) {
|
1310 |
+
if ($modify_files && $modify_db) {
|
1311 |
+
$out .= 'these tools <b>modify files & the database</b>';
|
1312 |
+
} elseif (!$modify_files && $modify_db) {
|
1313 |
+
$out .= 'these tools <b>modify the database</b> but they don\'t modify any files</b>';
|
1314 |
+
} elseif ($modify_files && !$modify_db) {
|
1315 |
+
$out .= 'these tools <b>modify files</b> but they don\'t modify the database</b>';
|
1316 |
+
}
|
1317 |
+
} else {
|
1318 |
+
if ($modify_files && $modify_db) {
|
1319 |
+
$out .= 'this tool <b>modifies files & the database</b>';
|
1320 |
+
} elseif (!$modify_files && $modify_db) {
|
1321 |
+
$out .= 'this tool <b>modifies the database</b> but it doesn\'t modify any files</b>';
|
1322 |
+
} elseif ($modify_files && !$modify_db) {
|
1323 |
+
$out .= 'this tool <b>modifies files</b> but it doesn\'t modify the database</b>';
|
1324 |
+
}
|
1325 |
+
}
|
1326 |
+
$out .= '</p>';
|
1327 |
|
1328 |
return $out;
|
1329 |
+
} // get_tool_icons
|
1330 |
|
1331 |
|
1332 |
/**
|
1347 |
echo '<header>';
|
1348 |
echo '<div class="wpr-container">';
|
1349 |
echo '<img id="logo-icon" src="' . $this->plugin_url . 'img/wp-reset-logo.png" title="' . __('WP Reset', 'wp-reset') . '" alt="' . __('WP Reset', 'wp-reset') . '">';
|
|
|
1350 |
echo '</div>';
|
1351 |
echo '</header>';
|
1352 |
|
1353 |
+
echo '<div id="loading-tabs"><img class="rotating" src="' . $this->plugin_url . 'img/wp-reset-icon.png' . '" alt="Loading. Please wait." title="Loading. Please wait."></div>';
|
1354 |
+
|
1355 |
+
echo '<div id="wp-reset-tabs" class="ui-tabs" style="display: none;">';
|
1356 |
|
1357 |
echo '<nav>';
|
1358 |
echo '<div class="wpr-container">';
|
1359 |
echo '<ul class="wpr-main-tab">';
|
1360 |
echo '<li><a href="#tab-reset">' . __('Reset', 'wp-reset') . '</a></li>';
|
1361 |
echo '<li><a href="#tab-tools">' . __('Tools', 'wp-reset') . '</a></li>';
|
1362 |
+
echo '<li><a href="#tab-snapshots">' . __('Snapshots', 'wp-reset') . '</a></li>';
|
1363 |
+
echo '<li><a href="#tab-collections">' . __('Collections', 'wp-reset') . '</a></li>';
|
1364 |
echo '<li><a href="#tab-support">' . __('Support', 'wp-reset') . '</a></li>';
|
1365 |
echo '</ul>';
|
1366 |
echo '</div>'; // container
|
1412 |
$questions[] = '<div class="question-wrapper" data-value="backup" title="Click to select/unselect answer">' .
|
1413 |
'<span class="dashicons dashicons-yes"></span>' .
|
1414 |
'<div class="question"><b>Off-site backups</b><br>' .
|
1415 |
+
'<i>Backup the site to Dropbox, FTP or Google Drive before using any tools</i></div>' .
|
1416 |
'</div>';
|
1417 |
|
1418 |
$questions[] = '<div class="question-wrapper" data-value="wpmu" title="Click to select/unselect answer">' .
|
1503 |
}
|
1504 |
|
1505 |
// ask for review
|
1506 |
+
if ((!empty($meta['reset_count']) || !empty($snapshots) || current_time('timestamp', true) - $meta['first_install'] > DAY_IN_SECONDS)
|
1507 |
&& false === $notice_shown
|
1508 |
&& false == $this->get_dismissed_notices('rate')
|
1509 |
) {
|
1528 |
|
1529 |
echo '<div class="card" id="card-description">';
|
1530 |
echo '<h4>';
|
1531 |
+
echo __('Please read carefully before proceeding', 'wp-reset');
|
1532 |
echo '<div class="card-header-right"><a class="toggle-card" href="#" title="' . __('Collapse / expand box', 'wp-reset') . '"><span class="dashicons dashicons-arrow-up-alt2"></span></a></div>';
|
1533 |
echo '</h4>';
|
1534 |
+
echo '<div class="card-body">';
|
1535 |
echo '<p><b class="red">' . __('Resetting will delete:', 'wp-reset') . '</b></p>';
|
1536 |
echo '<ul class="plain-list">';
|
1537 |
echo '<li>' . __('all posts, pages, custom post types, comments, media entries, users', 'wp-reset') . '</li>';
|
1538 |
echo '<li>' . __('all default WP database tables', 'wp-reset') . '</li>';
|
1539 |
echo '<li>' . sprintf(__('all custom database tables that have the same prefix "%s" as default tables in this installation', 'wp-reset'), $wpdb->prefix) . '</li>';
|
1540 |
+
echo '<li>' . __('always <a href="#" class="create-new-snapshot">create a snapshot</a> or a full backup, so you can restore it later', 'wp-reset') . '</li>';
|
1541 |
echo '</ul>';
|
1542 |
|
1543 |
echo '<p><b class="green">' . __('Resetting will not delete:', 'wp-reset') . '</b></p>';
|
1552 |
|
1553 |
echo '<p><b>' . __('What happens when I click the Reset button?', 'wp-reset') . '</b></p>';
|
1554 |
echo '<ul class="plain-list">';
|
1555 |
+
echo '<li>' . __('remember, always <a href="#" class="create-new-snapshot">make a snapshot</a> or a full backup first', 'wp-reset') . '</li>';
|
1556 |
+
echo '<li>' . __('you will have to confirm the action one more time', 'wp-reset') . '</li>';
|
1557 |
echo '<li>' . __('everything will be reset; see bullets above for details', 'wp-reset') . '</li>';
|
1558 |
echo '<li>' . __('site title, WordPress address, site address, site language, search engine visibility and current user will be restored', 'wp-reset') . '</li>';
|
1559 |
echo '<li>' . __('you will be logged out, automatically logged in and taken to the admin dashboard', 'wp-reset') . '</li>';
|
1571 |
} else {
|
1572 |
echo '<a href="#" class="open-webhooks-dialog">Install WP Webhooks & WPR addon</a> to automate your workflow, develop faster and connect WordPress to any web app or 3rd party system.';
|
1573 |
}
|
1574 |
+
echo '</p></div></div>'; // card description
|
1575 |
|
1576 |
$theme = wp_get_theme();
|
1577 |
|
1578 |
echo '<div class="card" id="card-reset">';
|
1579 |
+
echo '<h4>' . __('Site Reset', 'wp-reset');
|
1580 |
+
echo '<div class="card-header-right"><a class="toggle-card" href="#" title="' . __('Collapse / expand box', 'wp-reset') . '"><span class="dashicons dashicons-arrow-up-alt2"></span></a></div>';
|
1581 |
+
echo '</h4>';
|
1582 |
+
echo '<div class="card-body">';
|
1583 |
echo '<p><label for="reactivate-theme"><input name="wpr-post-reset[reactivate_theme]" type="checkbox" id="reactivate-theme" value="1"> ' . __('Reactivate current theme', 'wp-reset') . ' - ' . $theme->get('Name') . '</label></p>';
|
1584 |
echo '<p><label for="reactivate-wpreset"><input name="wpr-post-reset[reactivate_wpreset]" type="checkbox" id="reactivate-wpreset" value="1" checked> ' . __('Reactivate WP Reset plugin', 'wp-reset') . '</label></p>';
|
1585 |
if ($this->is_webhooks_active()) {
|
1591 |
} else {
|
1592 |
echo '<p>To run additional actions after reset or automate a complex workflow <a href="#" class="open-webhooks-dialog">install WP Webhooks & WPR addon</a>. It\'s a standard, platform-independent way of connecting WordPress to any web app. This <a href="https://www.youtube.com/watch?v=m8XDFXCNP9g" target="_blank">short video</a> explains it well.</p>';
|
1593 |
}
|
1594 |
+
echo '<p><br>' . __('Type <b>reset</b> in the confirmation field to confirm the reset and then click the "Reset WordPress" button.<br>Always <a href="#" class="create-new-snapshot" data-description="Before resetting the site">create a snapshot</a> before resetting if you want to be able to undo.', 'wp-reset') . '</p>';
|
1595 |
|
1596 |
wp_nonce_field('wp-reset');
|
1597 |
echo '<p><input id="wp_reset_confirm" type="text" name="wp_reset_confirm" placeholder="' . esc_attr__('Type in "reset"', 'wp-reset') . '" value="" autocomplete="off"> ';
|
1598 |
+
echo '<a id="wp_reset_submit" class="button button-delete">' . __('Reset Site', 'wp-reset') . '</a>' . $this->get_snapshot_button('reset-wordpress', 'Before resetting the site') . '</p>';
|
1599 |
+
echo '</div>';
|
1600 |
echo '</div>';
|
1601 |
} // tab_reset
|
1602 |
|
1608 |
*/
|
1609 |
private function tab_tools()
|
1610 |
{
|
1611 |
+
global $wpdb;
|
1612 |
+
|
1613 |
+
$tools = array(
|
1614 |
+
'tool-delete-transients' => 'Delete Transients',
|
1615 |
+
'tool-delete-uploads' => 'Clean Uploads Folder',
|
1616 |
+
'tool-reset-theme-options' => 'Reset Theme Options',
|
1617 |
+
'tool-delete-themes' => 'Delete Themes',
|
1618 |
+
'tool-delete-plugins' => 'Delete Plugins',
|
1619 |
+
'tool-empty-delete-custom-tables' => 'Empty or Delete Custom Tables',
|
1620 |
+
'tool-delete-htaccess' => 'Delete .htaccess File'
|
1621 |
+
);
|
1622 |
+
|
1623 |
echo '<div class="card">';
|
1624 |
+
echo $this->get_card_header(__('Index of Tools', 'wp-reset'), 'iot', true, false);
|
1625 |
+
echo '<div class="card-body">';
|
1626 |
+
$i = 0;
|
1627 |
+
$tools_nb = sizeof($tools);
|
1628 |
+
foreach ($tools as $tool_id => $tool_name) {
|
1629 |
+
if ($i == 0) {
|
1630 |
+
echo '<div class="half">';
|
1631 |
+
echo '<ul class="mb0 plain-list">';
|
1632 |
+
}
|
1633 |
+
if ($i == ceil($tools_nb / 2)) {
|
1634 |
+
echo '</div>';
|
1635 |
+
echo '<div class="half">';
|
1636 |
+
echo '<ul class="mb0 plain-list">';
|
1637 |
+
}
|
1638 |
+
|
1639 |
+
echo '<li><a title="Jump to ' . $tool_name . ' tool" class="scrollto" href="#' . $tool_id . '">' . $tool_name . '</a></li>';
|
1640 |
+
|
1641 |
+
if ($i == $tools_nb - 1) {
|
1642 |
+
echo '</ul>';
|
1643 |
+
echo '</div>'; // half
|
1644 |
+
}
|
1645 |
+
$i++;
|
1646 |
+
} // foreach tools
|
1647 |
+
echo '</div>';
|
1648 |
+
echo '</div>';
|
1649 |
+
|
1650 |
+
echo '<div class="card">';
|
1651 |
+
echo $this->get_card_header(__('Delete Transients', 'wp-reset'), 'tool-delete-transients', true, true);
|
1652 |
+
echo '<div class="card-body">';
|
1653 |
+
echo '<p>All transient related database entries will be deleted. Including expired and non-expired transients, and orphaned transient timeout entries.<br>Always <a href="#" data-description="Before deleting transients" class="create-new-snapshot">create a snapshot</a> before using this tool if you want to be able to undo its actions.</p>';
|
1654 |
+
echo $this->get_tool_icons(false, true);
|
1655 |
+
echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all transients?" data-btn-confirm="Delete all transients" data-text-wait="Deleting transients. Please wait." data-text-confirm="All database entries related to transients will be deleted. Always ' . esc_attr('<a data-description="Before deleting transients" href="#" class="create-new-snapshot">create a snapshot</a> if you want to be able to undo') . '." data-text-done="%n transient database entries have been deleted." data-text-done-singular="One transient database entry has been deleted." class="button button-delete" href="#" id="delete-transients">Delete all transients</a>' . $this->get_snapshot_button('delete-transients', 'Before deleting transients') . '</p>';
|
1656 |
+
echo '</div>';
|
1657 |
echo '</div>';
|
1658 |
|
1659 |
$upload_dir = wp_upload_dir(date('Y/m'), true);
|
1660 |
$upload_dir['basedir'] = str_replace(array('/', '\\'), DIRECTORY_SEPARATOR, $upload_dir['basedir']);
|
1661 |
|
1662 |
echo '<div class="card">';
|
1663 |
+
echo $this->get_card_header(__('Clean Uploads Folder', 'wp-reset'), 'tool-delete-uploads', true, true);
|
1664 |
+
echo '<div class="card-body">';
|
1665 |
echo '<p>' . __('All files in <code>' . $upload_dir['basedir'] . '</code> folder will be deleted. Including folders and subfolders, and files in subfolders. Files associated with <a href="' . admin_url('upload.php') . '">media</a> entries will be deleted too.<br><b>There is NO UNDO. WP Reset does not make any file backups.</b>', 'wp-reset') . '</p>';
|
1666 |
+
|
1667 |
+
echo $this->get_tool_icons(true, false);
|
1668 |
+
|
1669 |
if (false != $upload_dir['error']) {
|
1670 |
+
echo '<p class="mb0"><span style="color:#dd3036;"><b>Tool is not available.</b></span> Folder is not writeable by WordPress. Please check file and folder access rights.</p>';
|
1671 |
} else {
|
1672 |
+
echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all files & folders in uploads folder?" data-btn-confirm="Delete everything in uploads folder" data-text-wait="Deleting uploads. Please wait." data-text-confirm="All files and folders in uploads will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="%n files & folders have been deleted." data-text-done-singular="One file or folder has been deleted." class="button button-delete" href="#" id="delete-uploads">Delete all files & folders in uploads folder</a></p>';
|
1673 |
}
|
1674 |
echo '</div>';
|
1675 |
+
echo '</div>';
|
1676 |
|
1677 |
echo '<div class="card">';
|
1678 |
+
echo $this->get_card_header(__('Reset Theme Options', 'wp-reset'), 'tool-reset-theme-options', true, true);
|
1679 |
+
echo '<div class="card-body">';
|
1680 |
+
echo '<p>' . __('All options (mods) for all themes will be reset; not just for the active theme. The tool works only for themes that use the <a href="https://codex.wordpress.org/Theme_Modification_API" target="_blank">WordPress theme modification API</a>. If options are saved in some other, custom way they won\'t be reset.<br> Always <a href="#" class="create-new-snapshot" data-description="Before resetting theme options">create a snapshot</a> before using this tool if you want to be able to undo its actions.', 'wp-reset') . '</p>';
|
1681 |
+
echo $this->get_tool_icons(false, true);
|
1682 |
+
echo '<p class="mb0"><a data-confirm-title="Are you sure you want to reset all theme options?" data-btn-confirm="Reset theme options" data-text-wait="Resetting theme options. Please wait." data-text-confirm="All options (mods) for all themes will be reset. Always ' . esc_attr('<a data-description="Before resetting theme options" href="#" class="create-new-snapshot">create a snapshot</a> if you want to be able to undo') . '." data-text-done="Options for %n themes have been reset." data-text-done-singular="Options for one theme have been reset." class="button button-delete" href="#" id="reset-theme-options">Reset theme options</a>' . $this->get_snapshot_button('reset-theme-options', 'Before resetting theme options') . '</p>';
|
1683 |
+
echo '</div>';
|
1684 |
echo '</div>';
|
1685 |
|
1686 |
$theme = wp_get_theme();
|
1687 |
|
1688 |
echo '<div class="card">';
|
1689 |
+
echo $this->get_card_header(__('Delete Themes', 'wp-reset'), 'tool-delete-themes', true, true);
|
1690 |
+
echo '<div class="card-body">';
|
1691 |
echo '<p>' . __('All themes will be deleted. Including the currently active theme - ' . $theme->get('Name') . '.<br><b>There is NO UNDO. WP Reset does not make any file backups.</b>', 'wp-reset') . '</p>';
|
1692 |
+
|
1693 |
+
echo $this->get_tool_icons(true, true);
|
1694 |
+
|
1695 |
+
echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all themes?" data-btn-confirm="Delete all themes" data-text-wait="Deleting all themes. Please wait." data-text-confirm="All themes will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="%n themes have been deleted." data-text-done-singular="One theme has been deleted." class="button button-delete" href="#" id="delete-themes">Delete all themes</a></p>';
|
1696 |
+
echo '</div>';
|
1697 |
echo '</div>';
|
1698 |
|
1699 |
echo '<div class="card">';
|
1700 |
+
echo $this->get_card_header(__('Delete Plugins', 'wp-reset'), 'tool-delete-plugins', true, true);
|
1701 |
+
echo '<div class="card-body">';
|
1702 |
echo '<p>' . __('All plugins will be deleted except for WP Reset which will remain active.<br><b>There is NO UNDO. WP Reset does not make any file backups.</b>', 'wp-reset') . '</p>';
|
1703 |
+
|
1704 |
+
echo $this->get_tool_icons(true, true);
|
1705 |
+
|
1706 |
+
echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete all plugins?" data-btn-confirm="Delete plugins" data-text-wait="Deleting plugins. Please wait." data-text-confirm="All plugins except WP Reset will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="%n plugins have been deleted." data-text-done-singular="One plugin has been deleted." class="button button-delete" href="#" id="delete-plugins">Delete plugins</a></p>';
|
1707 |
+
echo '</div>';
|
1708 |
echo '</div>';
|
1709 |
|
|
|
1710 |
$custom_tables = $this->get_custom_tables();
|
1711 |
|
1712 |
echo '<div class="card">';
|
1713 |
+
echo $this->get_card_header(__('Empty or Delete Custom Tables', 'wp-reset'), 'tool-empty-delete-custom-tables', true, true);
|
1714 |
+
echo '<div class="card-body">';
|
1715 |
+
echo '<p>' . __('This action affects only custom tables with <code>' . $wpdb->prefix . '</code> prefix. Core WP tables and other tables in the database that do not have that prefix will not be deleted/emptied. Deleting (dropping) tables completely removes them from the database. Emptying (truncating) removes all content from them, but keeps the structure intact.<br>Always <a href="#" class="create-new-snapshot" data-description="Before deleting custom tables">create a snapshot</a> before using this tool if you want to be able to undo its actions.</p>', 'wp-reset');
|
1716 |
if ($custom_tables) {
|
1717 |
echo '<p>' . __('The following ' . sizeof($custom_tables) . ' custom tables are affected by this tool: ');
|
1718 |
foreach ($custom_tables as $tbl) {
|
1727 |
echo '<p>' . __('There are no custom tables. There\'s nothing for this tool to empty or delete.', 'wp-reset') . '</p>';
|
1728 |
$custom_tables_btns = ' disabled';
|
1729 |
}
|
|
|
|
|
1730 |
|
1731 |
+
echo $this->get_tool_icons(false, true, true);
|
1732 |
+
|
1733 |
+
echo '<p class="mb0"><a data-confirm-title="Are you sure you want to empty all custom tables?" data-btn-confirm="Empty custom tables" data-text-wait="Emptying custom tables. Please wait." data-text-confirm="All custom tables with prefix <code>' . $wpdb->prefix . '</code> will be emptied. Always ' . esc_attr('<a href="#" class="create-new-snapshot" data-description="Before emptying custom tables">create a snapshot</a> if you want to be able to undo') . '." data-text-done="%n custom tables have been emptied." data-text-done-singular="One custom table has been emptied." class="button button-delete' . $custom_tables_btns . '" href="#" id="truncate-custom-tables">Empty (truncate) custom tables</a>';
|
1734 |
+
echo '<a data-confirm-title="Are you sure you want to delete all custom tables?" data-btn-confirm="Delete custom tables" data-text-wait="Deleting custom tables. Please wait." data-text-confirm="All custom tables with prefix <code>' . $wpdb->prefix . '</code> will be deleted. Always ' . esc_attr('<a href="#" class="create-new-snapshot" data-description="Before deleting custom tables">create a snapshot</a> if you want to be able to undo') . '." data-text-done="%n custom tables have been deleted." data-text-done-singular="One custom table has been deleted." class="button button-delete' . $custom_tables_btns . '" href="#" id="drop-custom-tables">Delete (drop) custom tables</a>' . $this->get_snapshot_button('drop-custom-tables', 'Before deleting custom tables') . '</p>';
|
1735 |
+
echo '</div>';
|
1736 |
echo '</div>';
|
1737 |
|
1738 |
echo '<div class="card">';
|
1739 |
+
echo $this->get_card_header(__('Delete .htaccess File', 'wp-reset'), 'tool-delete-htaccess', true, true);
|
1740 |
+
echo '<div class="card-body">';
|
1741 |
echo '<p>' . __('This action deletes the .htaccess file located in <code>' . $this->get_htaccess_path() . '</code><br><b>There is NO UNDO. WP Reset does not make any file backups.</b></p>', 'wp-reset');
|
1742 |
|
1743 |
echo '<p>If you need to edit .htaccess, install our free <a href="' . admin_url('plugin-install.php?tab=plugin-information&plugin=wp-htaccess-editor&TB_iframe=true&width=600&height=550') . '" class="thickbox open-plugin-details-modal">WP Htaccess Editor</a> plugin. It automatically creates backups when you edit .htaccess as well as checks for syntax errors. To create the default .htaccess file open <a href="' . admin_url('options-permalink.php') . '">Settings - Permalinks</a> and re-save settings. WordPress will recreate the file.</p>';
|
1744 |
|
1745 |
+
echo $this->get_tool_icons(true, false);
|
1746 |
|
1747 |
+
echo '<p class="mb0"><a data-confirm-title="Are you sure you want to delete the .htaccess file?" data-btn-confirm="Delete .htaccess file" data-text-wait="Deleting .htaccess file. Please wait." data-text-confirm="Htaccess file will be deleted. There is NO UNDO. WP Reset does not make any file backups." data-text-done="Htaccess file has been deleted." data-text-done-singular="Htaccess file has been deleted." class="button button-delete" href="#" id="delete-htaccess">Delete .htaccess file</a></p>';
|
1748 |
+
|
1749 |
+
echo '</div>';
|
1750 |
echo '</div>';
|
1751 |
} // tab_tools
|
1752 |
|
1761 |
echo '<div class="card">';
|
1762 |
echo '<h4>' . __('What are Plugin & Theme Collections?', 'wp-reset') . '</h4>';
|
1763 |
echo '<p>' . __('A tool that\'s coming with WP Reset PRO that will <b>save hours & hours of your precious time</b>! Have a set of plugins (and themes) that you install and activate after every reset? Or on every fresh WP installation? Well, no more clicking install & active for ten minutes! Build the collection once and install it with one click as many times as needed.<br>WP Reset stores collections in the cloud so they\'re accessible on every site you build. You can use free plugins and themes from the official repo, and PRO ones by uploading a ZIP file. We\'ll safely store your license keys too, so you have everything in one place.', 'wp-reset') . '</p>';
|
1764 |
+
echo '<p><b>Interested in collections and other PRO features?</b> Ping us <a href="https://twitter.com/webfactoryltd" target="_blank">@webfactoryltd</a> and be among the first users who will get PRO in early January 2020.</p>';
|
1765 |
echo '</div>';
|
1766 |
} // tab_collections
|
1767 |
|
1783 |
echo '<p>' . __('We are very active on the <a href="https://wordpress.org/support/plugin/wp-reset" target="_blank">official WP Reset support forum</a>. If you found a bug, have a feature idea or just want to say hi - please drop by. We love to hear back from our users.', 'wp-reset') . '</p>';
|
1784 |
echo '</div>';
|
1785 |
|
|
|
|
|
|
|
|
|
|
|
1786 |
echo '<div class="card">';
|
1787 |
echo '<h4>' . __('Care to help out?', 'wp-reset') . '</h4>';
|
1788 |
echo '<p>' . __('No need for donations or anything like that :) If you can give us a <a href="https://wordpress.org/support/plugin/wp-reset/reviews/#new-post" target="_blank">five star rating</a> you\'ll help out more than you can imagine. A public mention <a href="https://twitter.com/webfactoryltd" target="_blank">@webfactoryltd</a> also does wonders. Thank you!', 'wp-reset') . '</p>';
|
1802 |
|
1803 |
echo '<div class="card" id="card-snapshots">';
|
1804 |
echo '<h4>';
|
1805 |
+
echo __('Snapshots', 'wp-reset');
|
1806 |
echo '<div class="card-header-right"><a class="toggle-card" href="#" title="' . __('Collapse / expand box', 'wp-reset') . '"><span class="dashicons dashicons-arrow-up-alt2"></span></a></div>';
|
1807 |
echo '</h4>';
|
1808 |
+
echo '<div class="card-body">';
|
1809 |
echo '<p>A snapshot is a copy of all WP database tables, standard and custom ones, saved in your database. Files are not saved or included in snapshots in any way. <a href="https://www.youtube.com/watch?v=xBfMmS12vMY" target="_blank">Watch a short video</a> overview and tutorial about Snapshots.</p>';
|
1810 |
+
echo '<p>Snapshots are primarily a development tool. When using various reset tools that alter the database be sure to create a snapshot. Shortcuts are available in the confirmation dialog. If you need a full backup that includes files, use a dedicated <a target="_blank" href="' . admin_url('plugin-install.php?s=backup&tab=search&type=term') . '">backup plugin</a>.</p>';
|
1811 |
echo '<p>Use snapshots to find out what changes a plugin made to your database or to quickly restore the dev environment after testing database related changes. Restoring a snapshot does not affect other snapshots, or WP Reset settings.</p>';
|
1812 |
|
1813 |
$table_status = $wpdb->get_results('SHOW TABLE STATUS');
|
1840 |
|
1841 |
echo '';
|
1842 |
echo '</div>';
|
1843 |
+
echo '</div>';
|
1844 |
|
1845 |
+
echo '<div class="card">';
|
1846 |
echo '<h4>';
|
1847 |
+
echo __('Snapshots', 'wp-reset');
|
1848 |
+
echo '<div class="card-header-right"><a id="create-new-snapshot-primary" data-msg-success="Snapshot created!" data-msg-wait="Creating snapshot. Please wait." data-btn-confirm="Create snapshot" data-placeholder="Snapshot name or brief description, ie: before plugin install" data-text="Enter snapshot name or brief description, up to 64 characters." data-title="Create a new snapshot" title="Create a new database snapshot" href="#" class="button button-primary create-new-snapshot">' . __('Create Snapshot', 'wp-reset') . '</a></div>';
|
1849 |
echo '</h4>';
|
1850 |
|
1851 |
if ($snapshots = $this->get_snapshots()) {
|
1852 |
+
$snapshots = array_reverse($snapshots);
|
1853 |
echo '<table id="wpr-snapshots">';
|
1854 |
+
echo '<tr><th>Date</th><th>Description</th><th class="ss-actions"> </th></tr>';
|
1855 |
foreach ($snapshots as $ss) {
|
1856 |
echo '<tr id="wpr-ss-' . $ss['uid'] . '">';
|
1857 |
if (!empty($ss['name'])) {
|
|
|
1858 |
$name = $ss['name'];
|
1859 |
} else {
|
|
|
1860 |
$name = 'created on ' . date(get_option('date_format'), strtotime($ss['timestamp'])) . ' @ ' . date(get_option('time_format'), strtotime($ss['timestamp']));
|
1861 |
}
|
1862 |
+
|
1863 |
+
echo '<td>';
|
1864 |
+
if (current_time('timestamp') - strtotime($ss['timestamp']) > 12 * HOUR_IN_SECONDS) {
|
1865 |
+
echo date(get_option('date_format'), strtotime($ss['timestamp'])) . '<br>@ ' . date(get_option('time_format'), strtotime($ss['timestamp']));
|
1866 |
+
} else {
|
1867 |
+
echo human_time_diff(strtotime($ss['timestamp']), current_time('timestamp')) . ' ago';
|
1868 |
+
}
|
1869 |
+
echo '</td>';
|
1870 |
+
//echo '<td title="Created on ' . date(get_option('date_format'), strtotime($ss['timestamp'])) . ' @ ' . date(get_option('time_format'), strtotime($ss['timestamp'])) . '">' . '' . date(get_option('date_format'), strtotime($ss['timestamp'])) . '<br>@ ' . date(get_option('time_format'), strtotime($ss['timestamp'])) . '</td>';
|
1871 |
+
|
1872 |
+
echo '<td>';
|
1873 |
+
if (!empty($ss['name'])) {
|
1874 |
+
echo '<b>' . $ss['name'] . '</b><br>';
|
1875 |
+
}
|
1876 |
+
echo $ss['tbl_core'] . ' standard & ';
|
1877 |
if ($ss['tbl_custom']) {
|
1878 |
echo $ss['tbl_custom'] . ' custom table' . ($ss['tbl_custom'] == 1 ? '' : 's');
|
1879 |
} else {
|
1881 |
}
|
1882 |
echo ' totaling ' . $this->format_size($ss['tbl_size']) . ' in ' . number_format($ss['tbl_rows']) . ' rows</td>';
|
1883 |
echo '<td>';
|
1884 |
+
echo '<div class="dropdown">
|
1885 |
+
<a class="button dropdown-toggle" href="#">Actions</a>
|
1886 |
+
<div class="dropdown-menu">';
|
1887 |
+
echo '<a data-title="Current DB tables compared to snapshot %s" data-wait-msg="Comparing. Please wait." data-name="' . $name . '" title="Compare snapshot to current database tables" href="#" class="ss-action compare-snapshot dropdown-item" data-ss-uid="' . $ss['uid'] . '">Compare snapshot to current data</a>';
|
1888 |
+
echo '<a data-btn-confirm="Restore snapshot" data-text-wait="Restoring snapshot. Please wait." data-text-confirm="Are you sure you want to restore the selected snapshot? There is NO UNDO.<br>Restoring the snapshot will delete all current standard and custom tables and replace them with tables from the snapshot." data-text-done="Snapshot has been restored. Click OK to reload the page with new data." title="Restore snapshot by overwriting current database tables" href="#" class="ss-action restore-snapshot dropdown-item" data-ss-uid="' . $ss['uid'] . '">Restore snapshot</a>';
|
1889 |
+
echo '<a data-success-msg="Snapshot export created!<br><a href=\'%s\'>Download it</a>" data-wait-msg="Exporting snapshot. Please wait." title="Download snapshot as gzipped SQL dump" href="#" class="ss-action download-snapshot dropdown-item" data-ss-uid="' . $ss['uid'] . '">Download snapshot</a>';
|
1890 |
+
echo '<a data-btn-confirm="Delete snapshot" data-text-wait="Deleting snapshot. Please wait." data-text-confirm="Are you sure you want to delete the selected snapshot and all its data? There is NO UNDO.<br>Deleting the snapshot will not affect the active database tables in any way." data-text-done="Snapshot has been deleted." title="Permanently delete snapshot" href="#" class="ss-action delete-snapshot dropdown-item" data-ss-uid="' . $ss['uid'] . '">Delete snapshot</a></div></div></td>';
|
1891 |
echo '</tr>';
|
1892 |
} // foreach
|
1893 |
echo '</table>';
|
2122 |
require_once $this->plugin_dir . 'libs/dumper.php';
|
2123 |
|
2124 |
try {
|
2125 |
+
$world_dumper = WPR_Shuttle_Dumper::create(array(
|
2126 |
'host' => DB_HOST,
|
2127 |
'username' => DB_USER,
|
2128 |
'password' => DB_PASSWORD,
|
2153 |
} // export_snapshot
|
2154 |
|
2155 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2156 |
/**
|
2157 |
* Replace current tables with ones in snapshot.
|
2158 |
*
|
2388 |
} elseif ($schema1 != $schema2) {
|
2389 |
require_once $this->plugin_dir . 'libs/diff.php';
|
2390 |
require_once $this->plugin_dir . 'libs/diff/Renderer/Html/SideBySide.php';
|
2391 |
+
$diff = new WPR_Diff(explode("\n", $tbl_current['schema']), explode("\n", $tbl_snapshot['schema']), array('ignoreWhitespace' => false));
|
2392 |
+
$renderer = new WPR_Diff_Renderer_Html_SideBySide;
|
2393 |
|
2394 |
$out2 .= '<div class="wpr-table-container" data-table="' . $tbl_current['basename'] . '">';
|
2395 |
$out2 .= '<table>';
|
2550 |
}
|
2551 |
}
|
2552 |
|
2553 |
+
if ($plugin_info && is_array($plugin_info)) {
|
2554 |
array_unshift($res->plugins, $plugin_info);
|
2555 |
}
|
2556 |
|
2571 |
$res = $this->add_plugin_featured('wp-force-ssl', $res);
|
2572 |
$res = $this->add_plugin_featured('eps-301-redirects', $res);
|
2573 |
|
|
|
2574 |
return $res;
|
2575 |
} // plugins_api_result
|
2576 |
|