Version Description
- added Wordpress login-less integration
- plugin settings are now saved to database
- security audit and hardening
Download this release
Release Info
Developer | xcloner |
Plugin | XCloner – Backup and Restore |
Version | 3.1.0 |
Comparing to | |
See all releases |
Code changes from version 3.0.1 to 3.1.0
- admin.cloner.html.php +336 -294
- admin.cloner.php +66 -82
- admin.xcloner-backupandrestore.php +0 -5
- admin.xcloner.php +0 -10
- administrator/.htaccess +2 -0
- administrator/backups/.htaccess +2 -0
- browser/files_inpage.php +1 -3
- browser/files_xml.php +8 -21
- browser/xmlhttp.js +7 -7
- classes/.htaccess +2 -0
- classes/DropboxClient.php +659 -0
- classes/OAuthSimple.php +532 -0
- classes/fileRecursion.php +7 -1
- classes/mysqlBackup.class.php +16 -24
- classes/phpseclib/Crypt/AES.php +594 -0
- classes/phpseclib/Crypt/DES.php +1245 -0
- classes/phpseclib/Crypt/Hash.php +824 -0
- classes/phpseclib/Crypt/RC4.php +505 -0
- classes/phpseclib/Crypt/RSA.php +2356 -0
- classes/phpseclib/Crypt/Random.php +133 -0
- classes/phpseclib/Crypt/Rijndael.php +1424 -0
- classes/phpseclib/Crypt/TripleDES.php +1009 -0
- classes/phpseclib/Math/BigInteger.php +3551 -0
- classes/phpseclib/Net/SFTP.php +1609 -0
- classes/phpseclib/Net/SSH1.php +1408 -0
- classes/phpseclib/Net/SSH2.php +2660 -0
- classes/phpseclib/PHP/Compat/Function/array_fill.php +41 -0
- classes/phpseclib/PHP/Compat/Function/bcpowmod.php +66 -0
- classes/phpseclib/PHP/Compat/Function/str_split.php +59 -0
- cloner.config.php +20 -21
- cloner.cron.php +281 -196
- cloner.functions.php +94 -66
- common.php +29 -19
- configs/.htaccess +2 -0
- configs/test.php +0 -53
- css/main.css +1 -1
- index.html +0 -0
- index.php +0 -3
- index2.php +0 -3
- install.xcloner.php +0 -25
- javascript/backup.js +45 -45
- javascript/dtree.js +14 -14
- javascript/jquery-1.4.4.min.js +0 -167
- javascript/jquery-ui-1.8.9.custom.min.js +0 -585
admin.cloner.html.php
CHANGED
@@ -24,9 +24,6 @@
|
|
24 |
/** ensure this file is being included by a parent file */
|
25 |
defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
|
26 |
|
27 |
-
if($_COOKIE['auth_clone'] != 1)
|
28 |
-
setcookie('auth_clone', '1');
|
29 |
-
|
30 |
class mosTabs{
|
31 |
|
32 |
function mosTabs($int){
|
@@ -66,28 +63,8 @@ function header(){
|
|
66 |
global $mosConfig_live_site, $task;
|
67 |
$excl_tasks = array("view", "config","");
|
68 |
|
69 |
-
/*if(!in_array($_REQUEST['task'], $excl_tasks)){
|
70 |
-
$seconds_to_cache = 3600;
|
71 |
-
$ts = gmdate("D, d M Y H:i:s", time() + $seconds_to_cache) . " GMT";
|
72 |
-
@header("Expires: $ts");
|
73 |
-
@header("Pragma: cache");
|
74 |
-
@header("Cache-Control: maxage=$seconds_to_cache");
|
75 |
-
}*/
|
76 |
?>
|
77 |
-
|
78 |
-
<head>
|
79 |
-
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
|
80 |
-
<title>XCloner Backup and Restore</title>
|
81 |
-
<META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
|
82 |
-
|
83 |
-
<link rel="styleSheet" href="css/dtree.css" type="text/css" />
|
84 |
-
<link rel="styleSheet" href="css/main.css" type="text/css" />
|
85 |
-
<link rel="styleSheet" href="css/start/jquery-ui-1.8.9.custom.css" type="text/css" />
|
86 |
-
|
87 |
-
<script type="text/javascript" src="javascript/dtree.js"></script>
|
88 |
-
<script type="text/javascript" src="javascript/main.js"></script>
|
89 |
-
<script type="text/javascript" src="javascript/jquery-1.4.4.min.js"></script>
|
90 |
-
<script type="text/javascript" src="javascript/jquery-ui-1.8.9.custom.min.js"></script>
|
91 |
<script type="text/javascript">
|
92 |
|
93 |
/* Optional: Temporarily hide the "tabber" class so it does not "flash"
|
@@ -97,9 +74,6 @@ function header(){
|
|
97 |
document.write('<style type="text/css">.tabber{display:none;}<\/style>');
|
98 |
</script>
|
99 |
|
100 |
-
</head>
|
101 |
-
<body>
|
102 |
-
|
103 |
<table width='100%' style="padding-left: 3px; padding-right: 4px;align:center;" bgcolor='#ffffff'>
|
104 |
<tr><td align='right'>
|
105 |
|
@@ -112,7 +86,7 @@ document.write('<style type="text/css">.tabber{display:none;}<\/style>');
|
|
112 |
<tr>
|
113 |
<td width='auto'>
|
114 |
<table><tr><td>
|
115 |
-
<img src="images/backup.png" align="middle">
|
116 |
</td><td>
|
117 |
<a href="index.php"><h2><?php echo LM_COM_TITLE.$_SERVER['HTTP_HOST']; ?></h2>
|
118 |
<h1>Backup and Restore</h1>
|
@@ -147,58 +121,34 @@ document.write('<style type="text/css">.tabber{display:none;}<\/style>');
|
|
147 |
|
148 |
d = new dTree('d');
|
149 |
|
150 |
-
d.add(0,-1,' <?php echo LM_MENU_CLONER;?>','
|
151 |
|
152 |
-
d.add(800,0,' <?php echo LM_MENU_ADMINISTRATION;?>','','','','images/actions.gif','images/actions.gif');
|
153 |
|
154 |
-
d.add(801,800,' <?php echo LM_MENU_CONFIGURATION;?>','
|
155 |
-
d.add(802,800,' <?php echo LM_MENU_CRON;?>','
|
156 |
-
d.add(803,800,' <?php echo LM_MENU_LANG;?>','
|
157 |
|
158 |
|
159 |
-
d.add(840,0,' <?php echo LM_MENU_ACTIONS;?>','','','','images/actions.gif','images/actions.gif');
|
160 |
-
d.add(841,840,' <?php echo LM_MENU_View_backups;?>','
|
161 |
-
d.add(842,840,' <?php echo LM_MENU_Generate_backup;?>','
|
162 |
-
d.add(843,840,' <?php echo LM_MENU_Restore_backup;?>','
|
163 |
|
164 |
-
d.add(830,0,' <?php echo LM_MENU_SUPPORT;?>','','','','images/support.png','images/support.png');
|
165 |
-
d.add(831,830,' <?php echo LM_MENU_FORUM;?>','http://www.xcloner.com/support/forums/','','_blank','images/forum.png','images/forum.png');
|
166 |
-
d.add(832,830,' <?php echo LM_MENU_WEBSITE;?>','http://www.xcloner.com','','_blank','images/website.png','images/website.png');
|
167 |
|
168 |
|
169 |
|
170 |
-
d.add(820,0,' <?php echo LM_MENU_Documentation;?>','','','','images/help.png','images/
|
171 |
-
d.add(821,820,' <?php echo LM_MENU_ABOUT;?>','
|
172 |
|
173 |
document.write(d);
|
174 |
|
175 |
//-->
|
176 |
</script></div> </td></tr></table>
|
177 |
|
178 |
-
<!--XCloner Ads -->
|
179 |
-
<br />
|
180 |
-
<table width='100%' cellpadding='5' height='100%' class='menu_table'><tr><td>
|
181 |
-
<center>
|
182 |
-
|
183 |
-
<script type='text/javascript'><!--//<![CDATA[
|
184 |
-
var m3_u = (location.protocol=='https:'?'https://www.xcloner.com/ads/www/delivery/ajs.php':'http://www.xcloner.com/ads/www/delivery/ajs.php');
|
185 |
-
var m3_r = Math.floor(Math.random()*99999999999);
|
186 |
-
if (!document.MAX_used) document.MAX_used = ',';
|
187 |
-
document.write ("<scr"+"ipt type='text/javascript' src='"+m3_u);
|
188 |
-
document.write ("?campaignid=3");
|
189 |
-
document.write ('&cb=' + m3_r);
|
190 |
-
if (document.MAX_used != ',') document.write ("&exclude=" + document.MAX_used);
|
191 |
-
document.write (document.charset ? '&charset='+document.charset : (document.characterSet ? '&charset='+document.characterSet : ''));
|
192 |
-
document.write ("&loc=" + escape(window.location));
|
193 |
-
if (document.referrer) document.write ("&referer=" + escape(document.referrer));
|
194 |
-
if (document.context) document.write ("&context=" + escape(document.context));
|
195 |
-
if (document.mmm_fo) document.write ("&mmm_fo=1");
|
196 |
-
document.write ("'><\/scr"+"ipt>");
|
197 |
-
//]]>--></script><noscript><a href='http://www.xcloner.com/ads/www/delivery/ck.php?n=a6255e1e&cb=1675675575' target='_blank'><img src='http://www.xcloner.com/ads/www/delivery/avw.php?campaignid=3&cb=1675675575&n=a6255e1e' border='0' alt='' /></a></noscript>
|
198 |
-
|
199 |
-
</center>
|
200 |
-
</td></td></table>
|
201 |
-
<!-- END Ads -->
|
202 |
|
203 |
</td><td valign='top' align='left' style="padding-left: 20px;">
|
204 |
|
@@ -219,8 +169,12 @@ function footer(){
|
|
219 |
<p>Powered by <a href='http://www.xcloner.com' target='_blank'>XCloner</a>. Backup and Restore Made Easy!</p></center>
|
220 |
|
221 |
</td></tr></table>
|
222 |
-
<script>
|
223 |
-
|
|
|
|
|
|
|
|
|
224 |
|
225 |
<?php
|
226 |
|
@@ -237,7 +191,7 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
|
|
237 |
echo "<h2>Initializing backup...</h2>";
|
238 |
echo "<h3 >Backup <b>$filename</b> created, we may continue!</h3><br />";
|
239 |
|
240 |
-
$urlReturn = "
|
241 |
|
242 |
if(!$_CONFIG['refresh_mode']){
|
243 |
|
@@ -253,7 +207,7 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
|
|
253 |
<!--Start ProgressBar-->
|
254 |
<script type="text/javascript">
|
255 |
|
256 |
-
|
257 |
|
258 |
var globalUrl;
|
259 |
var step = "r1";
|
@@ -265,14 +219,14 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
|
|
265 |
var parts = 0;
|
266 |
var oldSize = 0;
|
267 |
|
268 |
-
|
269 |
|
270 |
-
|
271 |
"error":function(request, status, error) {
|
272 |
//reset state here;
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
}});
|
277 |
|
278 |
function getSize(bytes, conv){
|
@@ -291,41 +245,41 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
|
|
291 |
globalUrl = url;
|
292 |
step = "r1";
|
293 |
|
294 |
-
|
295 |
|
296 |
if(!json){
|
297 |
-
|
298 |
-
|
299 |
}
|
300 |
|
301 |
if(json.dumpsize && !json.endDump){
|
302 |
-
|
303 |
}
|
304 |
|
305 |
if(json.newDump){
|
306 |
count++;
|
307 |
-
|
308 |
if(json.databaseName!="")
|
309 |
-
|
310 |
counter = parseInt(json.startAtLine);
|
311 |
|
312 |
}else{
|
313 |
-
|
314 |
}
|
315 |
|
316 |
if(!parseInt(json.finished)){
|
317 |
//get next records
|
318 |
|
319 |
-
|
320 |
|
321 |
-
recurseUrl = "
|
322 |
xclonerRecurseMYSQL(recurseUrl);
|
323 |
|
324 |
}
|
325 |
else{
|
326 |
|
327 |
-
|
328 |
-
var recurseUrl="
|
329 |
xclonerRecurseJSON(recurseUrl);
|
330 |
|
331 |
}
|
@@ -336,42 +290,42 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
|
|
336 |
|
337 |
function xclonerRecurseJSON(url){
|
338 |
//scan file system
|
339 |
-
|
340 |
|
341 |
globalUrl = url;
|
342 |
step = "r2";
|
343 |
|
344 |
-
|
345 |
|
346 |
if(!json){
|
347 |
-
|
348 |
-
|
349 |
}
|
350 |
|
351 |
if(!parseInt(json.finished)){
|
352 |
|
353 |
-
|
354 |
|
355 |
-
var recurseUrl = "
|
356 |
xclonerRecurseJSON(recurseUrl);
|
357 |
|
358 |
}
|
359 |
else{
|
360 |
var size = parseFloat(json.size)/(1024*1024);
|
361 |
-
|
362 |
-
|
363 |
|
364 |
if(json.overlimit.length > 0){
|
365 |
-
|
366 |
for(var i=0; i < json.overlimit.length; i++){
|
367 |
|
368 |
-
|
369 |
|
370 |
}
|
371 |
}
|
372 |
|
373 |
//xclonerGetJSON("<?php echo $urlReturn;?>");
|
374 |
-
returnUrl = "
|
375 |
xclonerGetJSON(returnUrl);
|
376 |
|
377 |
}
|
@@ -385,19 +339,19 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
|
|
385 |
globalUrl = url;
|
386 |
step = "r3";
|
387 |
|
388 |
-
|
389 |
|
390 |
if(!json){
|
391 |
-
|
392 |
-
|
393 |
}
|
394 |
|
395 |
var percent = parseInt(json.percent);
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
if(!json.finished){
|
402 |
|
403 |
if(oldBackupName != json.backup){
|
@@ -408,31 +362,31 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
|
|
408 |
oldSize = parseInt(json.backupSize);
|
409 |
}
|
410 |
|
411 |
-
var url = "
|
412 |
xclonerGetJSON(url);
|
413 |
}else{
|
414 |
|
415 |
//all done
|
416 |
-
url = "
|
417 |
-
|
418 |
});
|
419 |
|
420 |
-
|
421 |
-
|
422 |
if(parts > 0){
|
423 |
-
|
424 |
-
|
425 |
}
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
modal: true,
|
432 |
width: 600,
|
433 |
buttons: {
|
434 |
Close: function() {
|
435 |
-
|
436 |
}
|
437 |
}
|
438 |
});
|
@@ -445,9 +399,9 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
|
|
445 |
|
446 |
//Main program here
|
447 |
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
if(step == "r1"){
|
452 |
xclonerRecurseMYSQL(globalUrl);
|
453 |
}
|
@@ -460,15 +414,15 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
|
|
460 |
}
|
461 |
});
|
462 |
|
463 |
-
|
464 |
-
|
465 |
|
466 |
if(dbbackup){
|
467 |
-
recurseUrl = "
|
468 |
xclonerRecurseMYSQL(recurseUrl);
|
469 |
}else{
|
470 |
-
|
471 |
-
var recurseUrl="
|
472 |
xclonerRecurseJSON(recurseUrl);
|
473 |
|
474 |
}
|
@@ -509,7 +463,7 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
|
|
509 |
<div id="complete">
|
510 |
<br /><h2>Backup completed!</h2>
|
511 |
|
512 |
-
<form action="
|
513 |
<input type=hidden name=files[1] value='<?php echo $backupFile?>'>
|
514 |
<input type=hidden name=cid[1] value='<?php echo $backupFile?>'>
|
515 |
<input type="hidden" name="option" value="<?php echo $option; ?>"/>
|
@@ -581,10 +535,10 @@ function path_check($path){
|
|
581 |
}
|
582 |
|
583 |
function _FDefault(){
|
584 |
-
global $_CONFIG;
|
585 |
?>
|
586 |
|
587 |
-
<form action="
|
588 |
|
589 |
<table class="adminform">
|
590 |
<tr><th valign='top' >
|
@@ -599,8 +553,8 @@ function _FDefault(){
|
|
599 |
<div style="float:left;">
|
600 |
<div class="icon">
|
601 |
|
602 |
-
<a href="
|
603 |
-
<img src="images/settings.png"
|
604 |
alt="Settings" align="middle" name="" border="0" />
|
605 |
<span><?php echo LM_MAIN_Settings?></span>
|
606 |
</a>
|
@@ -610,8 +564,8 @@ function _FDefault(){
|
|
610 |
<div style="float:left;">
|
611 |
<div class="icon">
|
612 |
|
613 |
-
<a href="
|
614 |
-
<img src="images/editions.png"
|
615 |
alt="View Backups" align="middle" name="" border="0" />
|
616 |
<span><?php echo LM_MAIN_View_Backups?></span>
|
617 |
</a>
|
@@ -621,8 +575,8 @@ function _FDefault(){
|
|
621 |
<div style="float:left;">
|
622 |
<div class="icon">
|
623 |
|
624 |
-
<a href="
|
625 |
-
<img src="images/wizard.png"
|
626 |
alt="MagaGenerate Backup" align="middle" name="" border="0" />
|
627 |
<span><?php echo LM_MAIN_Generate_Backup?></span>
|
628 |
</a>
|
@@ -632,8 +586,8 @@ function _FDefault(){
|
|
632 |
<div style="float:left;">
|
633 |
<div class="icon">
|
634 |
|
635 |
-
<a href="
|
636 |
-
<img src="images/lhelp.png"
|
637 |
alt="MagaGenerate Backup" align="middle" name="" border="0" />
|
638 |
<span><?php echo LM_MAIN_Help?></span>
|
639 |
</a>
|
@@ -656,15 +610,20 @@ $error = 0;
|
|
656 |
<div class="status">
|
657 |
<span class="mtext">Backup Start Path Check: </span>
|
658 |
<?php
|
659 |
-
|
660 |
-
$stat =
|
661 |
|
662 |
if( $stat['code'] > 0 and $stat['code'] < 3){
|
663 |
echo "<span class='error'>".$stat['message']; $error = 1;
|
664 |
}
|
665 |
else{
|
666 |
echo "<span class='success'>OK";
|
667 |
-
|
|
|
|
|
|
|
|
|
|
|
668 |
echo " ($_CONFIG[backup_start_path])";
|
669 |
?>
|
670 |
</span></div>
|
@@ -673,7 +632,7 @@ $error = 0;
|
|
673 |
<span class="mtext">Backup Store Path Check: </span>
|
674 |
<?php
|
675 |
|
676 |
-
$stat =
|
677 |
|
678 |
if( $stat['code'] > 0){
|
679 |
echo "<span class='error'>".$stat['message']; $error = 1;
|
@@ -690,7 +649,7 @@ $error = 0;
|
|
690 |
<span class="mtext">Temporary Path Check: </span>
|
691 |
<?php
|
692 |
|
693 |
-
$stat =
|
694 |
|
695 |
if( $stat['code'] > 0){
|
696 |
echo "<span class='error'>".$stat['message']; $error = 1;
|
@@ -702,19 +661,19 @@ $error = 0;
|
|
702 |
?>
|
703 |
</span></div>
|
704 |
|
705 |
-
|
706 |
<span class="mtext">Authentication: </span>
|
707 |
<?php
|
708 |
|
709 |
if($_CONFIG['jcpass'] == md5('admin')){
|
710 |
-
echo "<span class='error'>Change default password 'admin'"; $error = 1;
|
711 |
}
|
712 |
else{
|
713 |
-
echo "<span class='success'>OK";
|
714 |
}
|
715 |
|
716 |
?>
|
717 |
-
</span></div
|
718 |
|
719 |
<div class="status">
|
720 |
<span class="mtext">Backup Ready: </span>
|
@@ -747,39 +706,43 @@ function Login(){
|
|
747 |
<center><br />
|
748 |
|
749 |
<script>
|
750 |
-
|
751 |
-
|
752 |
icons: {
|
753 |
primary: "ui-icon-locked"
|
754 |
}
|
755 |
-
})
|
756 |
-
|
|
|
|
|
|
|
|
|
|
|
757 |
icons: {
|
758 |
primary: "ui-icon-trash"
|
759 |
}
|
760 |
})
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
|
767 |
});
|
768 |
</script>
|
769 |
|
770 |
|
771 |
<div class="loginform">
|
772 |
-
<form action="
|
773 |
<table class="loginForm">
|
774 |
<tr><td align='center'>
|
775 |
<table align='center' cellpadding='10' cellspacing='20'>
|
776 |
<tr ><td colspan='2' align='center'><b>Authentication Area:</b></td></tr>
|
777 |
-
<tr><td>Username:</td><td><input type='text' size='30' name='username'></td></tr>
|
778 |
-
<tr><td>Password:</td><td><input type='password' size='30' name='password'></td></tr>
|
779 |
<tr><td> </td><td>
|
780 |
<div class="loginform">
|
781 |
-
<button>Login</button>
|
782 |
-
<button>Reset</button>
|
783 |
|
784 |
|
785 |
</div>
|
@@ -805,8 +768,8 @@ function Cron(){
|
|
805 |
?>
|
806 |
|
807 |
<script>
|
808 |
-
|
809 |
-
|
810 |
});
|
811 |
</script>
|
812 |
|
@@ -822,19 +785,12 @@ function Cron(){
|
|
822 |
<br /><br />
|
823 |
|
824 |
<ul>
|
825 |
-
<li><input type="text" value="/usr/bin/php <?php echo dirname(__FILE__);?>/cloner.cron.php" size="150" /></li>
|
826 |
-
<li><strong>curl http://website/path_to_xcloner_folder/cloner.cron.php</strong></li>
|
827 |
-
<li><strong>wget -q http://website/path_to_xcloner_folder/cloner.cron.php</strong></li>
|
828 |
-
<li><strong>lynx -sourcehttp://website/path_to_xcloner_folder/cloner.cron.php</strong></li>
|
829 |
</ul>
|
830 |
<br /><br />
|
831 |
|
832 |
For <b>Running Multiple Crons</b>, you need to first create a custom configuration file in the XCloner Configuration -> Cron tab
|
833 |
-
and then replace "cloner.cron.php" with "cloner.cron.php
|
834 |
-
<br /><br />
|
835 |
-
|
836 |
-
If you would like to use the <b>php SSH command</b> for running Multiple Crons, you will need to replace
|
837 |
-
the "cloner.cron.php" with <b>"cloner.cron.php myconfig.php"</b> in the command line.
|
838 |
<br /><br />
|
839 |
|
840 |
<?php echo LM_CRON_HELP?>
|
@@ -850,7 +806,7 @@ function Cron(){
|
|
850 |
function Translator_Edit_DEFAULT($option, $content, $file, $lang){
|
851 |
global $_CONFIG;
|
852 |
?>
|
853 |
-
<form action="
|
854 |
<table class="adminlist">
|
855 |
<tr>
|
856 |
<th align="left"><?php echo LM_LANG_EDIT_FILE?> <?php echo $file?></th>
|
@@ -876,7 +832,7 @@ function Translator_Edit_DEFAULT($option, $content, $file, $lang){
|
|
876 |
function Translator_Add($option){
|
877 |
global $_CONFIG;
|
878 |
?>
|
879 |
-
<form action="
|
880 |
<table class="adminlist">
|
881 |
<tr>
|
882 |
<th align="left"><?php echo LM_LANG_NEW?></th>
|
@@ -901,7 +857,7 @@ function Translator_Edit($option, $data, $def_data, $file, $lang){
|
|
901 |
global $_CONFIG;
|
902 |
?>
|
903 |
|
904 |
-
<form action="
|
905 |
<table class="adminlist">
|
906 |
<tr>
|
907 |
<th align="left"><?php echo LM_LANG_EDIT_FILE?> <input type=text name='lfile' size=100 value='<?php echo $file?>'><br />
|
@@ -976,14 +932,14 @@ function Translator($option, $lang_arr){
|
|
976 |
|
977 |
?>
|
978 |
<script>
|
979 |
-
|
980 |
-
|
981 |
-
|
982 |
-
|
983 |
});
|
984 |
</script>
|
985 |
|
986 |
-
<form action="
|
987 |
<div id="checklist">
|
988 |
<table class="adminlist">
|
989 |
<tr>
|
@@ -1008,7 +964,7 @@ function Translator($option, $lang_arr){
|
|
1008 |
<input type="hidden" name="files[<?php echo $i?>]" value="<?php echo $lang_arr[$i] ?>" />
|
1009 |
</td>
|
1010 |
<td align="left" >
|
1011 |
-
<a href="
|
1012 |
</td>
|
1013 |
</tr>
|
1014 |
<?php
|
@@ -1032,15 +988,49 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1032 |
|
1033 |
?>
|
1034 |
|
1035 |
-
<script>
|
1036 |
-
|
1037 |
-
|
1038 |
-
|
1039 |
-
|
1040 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1041 |
</script>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1042 |
<div id="checklist">
|
1043 |
-
<form action="
|
1044 |
<table class="adminlist">
|
1045 |
<tr>
|
1046 |
<th width="100">
|
@@ -1063,7 +1053,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1063 |
$k = 0;
|
1064 |
for ($i=0; $i <= (count( $files )-1); $i++) {
|
1065 |
$date = date ("D jS M Y H:i:s (\G\M\T O)", filemtime($path.'/'.$files[$i]));
|
1066 |
-
$url = "
|
1067 |
?>
|
1068 |
<tr class="<?php echo "row$k"; ?>">
|
1069 |
|
@@ -1073,7 +1063,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1073 |
<input type="hidden" name="files[<?php echo $i?>]" value="<?php echo $files[$i] ?>" />
|
1074 |
</td>
|
1075 |
<td align="left">
|
1076 |
-
<a target='_blank' href="<?php echo $url ?>"><img src="images/filesave.png" border="0" title="<?php echo LM_DOWNLOAD_TITLE." - ".$files[$i] ?>" /></a>
|
1077 |
</td>
|
1078 |
<td>
|
1079 |
<span class="backup_name"><?php echo $files[$i]; ?></span>
|
@@ -1105,31 +1095,33 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1105 |
function Config($option){
|
1106 |
global $config_file,$_CONFIG, $lang_array, $database, $mosConfig_db;
|
1107 |
?>
|
1108 |
-
<form name='adminForm' action='
|
1109 |
|
1110 |
<script>
|
1111 |
-
|
1112 |
-
|
1113 |
});
|
1114 |
|
1115 |
-
|
1116 |
-
|
1117 |
-
|
1118 |
-
|
1119 |
-
|
1120 |
-
|
1121 |
-
|
1122 |
-
|
1123 |
-
|
1124 |
-
|
1125 |
-
|
1126 |
-
|
1127 |
-
|
1128 |
-
|
1129 |
-
|
1130 |
-
|
1131 |
-
|
1132 |
-
|
|
|
|
|
1133 |
});
|
1134 |
</script>
|
1135 |
|
@@ -1138,16 +1130,16 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1138 |
|
1139 |
<li><a href="#tabs-1"><?php echo LM_TAB_GENERAL;?></a></li>
|
1140 |
<li><a href="#tabs-2"><?php echo LM_TAB_MYSQL;?></a></li>
|
1141 |
-
|
1142 |
<li><a href="#tabs-4"><?php echo LM_TAB_SYSTEM;?></a></li>
|
1143 |
<li><a href="#tabs-5"><?php echo LM_TAB_CRON;?></a></li>
|
1144 |
<li><a href="#tabs-6"><?php echo LM_TAB_INFO;?></a></li>
|
1145 |
</ul>
|
1146 |
|
1147 |
<table class='adminform'>
|
1148 |
-
|
1149 |
-
<?php echo LM_CONFIG_EDIT?> <?php echo $config_file?>
|
1150 |
-
</th></tr
|
1151 |
</table>
|
1152 |
<?php
|
1153 |
$tabs->startTab(LM_TAB_GENERAL,"1");
|
@@ -1202,18 +1194,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1202 |
</td>
|
1203 |
</tr>
|
1204 |
|
1205 |
-
|
1206 |
-
<td>
|
1207 |
-
<?php echo LM_CRON_COMPRESS?>
|
1208 |
-
</td>
|
1209 |
-
<td>
|
1210 |
-
<div id="radiog2">
|
1211 |
-
<label for="radiog21"><?php echo LM_YES?></label> <input id="radiog21" type=radio size=50 value=1 name='backup_compress' <?php if($_CONFIG[backup_compress]==1) echo 'checked';?>>
|
1212 |
-
<label for="radiog22"><?php echo LM_NO?></label> <input id="radiog22" type=radio size=50 value=0 name='backup_compress' <?php if($_CONFIG[backup_compress]==0) echo 'checked';?>>
|
1213 |
-
<br /> <small>set it to Yes in order to compress the files into smaller backups</small>
|
1214 |
-
</div>
|
1215 |
-
</td>
|
1216 |
-
</tr>
|
1217 |
|
1218 |
<tr>
|
1219 |
<td>
|
@@ -1221,8 +1202,8 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1221 |
</td>
|
1222 |
<td>
|
1223 |
<div id="radiog3">
|
1224 |
-
<label for="radiog31">Yes</label> <input id="radiog31" type=radio size=50 value=1 name='enable_db_backup' <?php if($_CONFIG[enable_db_backup]==1) echo 'checked';?>>
|
1225 |
-
<label for="radiog32">No</label> <input id="radiog32" type=radio size=50 value=0 name='enable_db_backup' <?php if($_CONFIG[enable_db_backup]==0) echo 'checked';?>>
|
1226 |
<br /><?php echo LM_CRON_DB_BACKUP_SUB?>
|
1227 |
</div>
|
1228 |
|
@@ -1255,7 +1236,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1255 |
<?php echo LM_CONFIG_MEM?>
|
1256 |
</td>
|
1257 |
<td align='left'>
|
1258 |
-
<table style="width:auto; margin-bottom: 10px;" cellpadding='0' cellspacing='2' border='
|
1259 |
<tr bgcolor='#efefef'><td style="width:70px;">
|
1260 |
<label for="checktar"><?php echo LM_ACTIVE;?></label> <input type=checkbox id="checktar" value=1 name='mem' <?php if($_CONFIG[mem]==1) echo 'checked';?>>
|
1261 |
</td><td align='left'>
|
@@ -1287,7 +1268,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1287 |
</p></div>
|
1288 |
</div>
|
1289 |
|
1290 |
-
|
1291 |
<h3><a href="#">Public Key Management</a></h3>
|
1292 |
<div><p>
|
1293 |
<table class='adminForm'>
|
@@ -1305,7 +1286,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1305 |
|
1306 |
</table>
|
1307 |
</p></div>
|
1308 |
-
</div
|
1309 |
|
1310 |
</div>
|
1311 |
|
@@ -1379,7 +1360,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1379 |
</div>
|
1380 |
<?php
|
1381 |
$tabs->endTab();
|
1382 |
-
|
1383 |
?>
|
1384 |
<div id="configtabinside">
|
1385 |
<div>
|
@@ -1410,7 +1391,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1410 |
</div>
|
1411 |
</div>
|
1412 |
<?php
|
1413 |
-
$tabs->endTab()
|
1414 |
$tabs->startTab(LM_TAB_SYSTEM,"4");
|
1415 |
?>
|
1416 |
|
@@ -1462,7 +1443,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1462 |
</td><td>
|
1463 |
<div id="radioftps">
|
1464 |
<label for="radioftps1">Normal</label><input id="radioftps1" type=radio size=50 value=0 name='secure_ftp' <?php if($_CONFIG[secure_ftp]==0) echo 'checked';?>>
|
1465 |
-
<label for="radioftps2">Secure</label><input id="radioftps2" type=radio size=50 value=1 name='secure_ftp' <?php if($_CONFIG[secure_ftp]==1) echo 'checked';?>>
|
1466 |
</td>
|
1467 |
</tr>
|
1468 |
|
@@ -1474,54 +1455,54 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1474 |
<div><p>
|
1475 |
|
1476 |
<script>
|
1477 |
-
|
1478 |
-
|
1479 |
value:parseInt(<?php echo $_CONFIG[backup_refresh_number];?>),
|
1480 |
min: 10,
|
1481 |
max: 1000,
|
1482 |
step: 10,
|
1483 |
slide: function( event, ui ) {
|
1484 |
-
|
1485 |
}
|
1486 |
});
|
1487 |
-
|
1488 |
});
|
1489 |
-
|
1490 |
-
|
1491 |
value:parseInt(<?php echo $_CONFIG[recordsPerSession];?>),
|
1492 |
min: 100,
|
1493 |
max: 100000,
|
1494 |
step: 100,
|
1495 |
slide: function( event, ui ) {
|
1496 |
-
|
1497 |
}
|
1498 |
});
|
1499 |
-
|
1500 |
});
|
1501 |
-
|
1502 |
-
|
1503 |
value:parseInt(<?php echo $_CONFIG[excludeFilesSize];?>),
|
1504 |
min: -1,
|
1505 |
max: 10240,
|
1506 |
step: 1,
|
1507 |
slide: function( event, ui ) {
|
1508 |
-
|
1509 |
}
|
1510 |
});
|
1511 |
-
|
1512 |
});
|
1513 |
|
1514 |
-
|
1515 |
-
|
1516 |
value:parseInt(<?php echo $_CONFIG[splitBackupSize];?>),
|
1517 |
min: -1,
|
1518 |
max: 10000,
|
1519 |
step: 1,
|
1520 |
slide: function( event, ui ) {
|
1521 |
-
|
1522 |
}
|
1523 |
});
|
1524 |
-
|
1525 |
});
|
1526 |
</script>
|
1527 |
|
@@ -1574,6 +1555,19 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1574 |
<input type=text size=20 name='refresh_time' value=<?php echo $_CONFIG[refresh_time];?>> miliseconds
|
1575 |
|
1576 |
</td></tr>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1577 |
|
1578 |
<tr><td>
|
1579 |
<?php echo LM_REFRESH_MODE?>
|
@@ -1624,18 +1618,18 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1624 |
</td>
|
1625 |
<td>
|
1626 |
<?php
|
1627 |
-
|
1628 |
-
if ($handle =
|
1629 |
|
1630 |
while (false !== ($file = readdir($handle))) {
|
1631 |
if( ($file!=".") && ($file!="..") &&($file!="") && (strstr($file, '.php'))){
|
1632 |
-
$fcron =
|
1633 |
|
1634 |
echo "<b>$fcron</b>";
|
1635 |
|
1636 |
echo " - <a href='$fcron' target='_blank'>execute cron</a>";
|
1637 |
|
1638 |
-
echo " | <a href='
|
1639 |
|
1640 |
echo "\n<br />";
|
1641 |
}
|
@@ -1712,7 +1706,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1712 |
</tr>
|
1713 |
|
1714 |
|
1715 |
-
|
1716 |
<td>
|
1717 |
<?php echo LM_CRON_IP?>
|
1718 |
</td>
|
@@ -1720,7 +1714,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1720 |
<textarea type=text size=50 name='cron_ip' cols='30' rows='5'><?php echo $_CONFIG[cron_ip]?></textarea> <br />
|
1721 |
<?php echo LM_CRON_IP_SUB?>
|
1722 |
</td>
|
1723 |
-
</tr
|
1724 |
</table>
|
1725 |
</p></div>
|
1726 |
</div>
|
@@ -1787,6 +1781,9 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1787 |
<td>
|
1788 |
<label for="cron_amazon_active"><?php echo LM_AMAZON_S3_ACTIVATE?></label>
|
1789 |
<input id="cron_amazon_active" type=checkbox name='cron_amazon_active' <?php if($_CONFIG[cron_amazon_active]==1) echo "checked";?> value='1'>
|
|
|
|
|
|
|
1790 |
</td>
|
1791 |
</tr>
|
1792 |
|
@@ -1807,7 +1804,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1807 |
<input type=text size=50 name='cron_amazon_awsSecretKey' value="<?php echo $_CONFIG['cron_amazon_awsSecretKey'];?>">
|
1808 |
</td>
|
1809 |
</tr>
|
1810 |
-
|
1811 |
<tr>
|
1812 |
<td width='200'>
|
1813 |
<?php echo LM_AMAZON_S3_BUCKET;?>
|
@@ -1830,6 +1827,56 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1830 |
</p></div>
|
1831 |
</div>
|
1832 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1833 |
<div>
|
1834 |
<h3><a href="#"> <?php echo LM_CRON_EMAIL_DETAILS?></a></h3>
|
1835 |
<div><p>
|
@@ -1863,7 +1910,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1863 |
</tr>
|
1864 |
|
1865 |
<?php
|
1866 |
-
if((abs($_CONFIG[system_mdatabases])==0) && ($_CONFIG[enable_db_backup]==1)){
|
1867 |
?>
|
1868 |
<tr><td valign='top'>
|
1869 |
<?php echo LM_DATABASE_INCLUDE_DATABASES?>
|
@@ -1873,8 +1920,8 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1873 |
|
1874 |
$curent_dbs = explode(",", $_CONFIG['databases_incl_list']);
|
1875 |
|
1876 |
-
$query =
|
1877 |
-
while($row =
|
1878 |
|
1879 |
$table = $row[0];
|
1880 |
|
@@ -1906,17 +1953,17 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
1906 |
<div><p>
|
1907 |
|
1908 |
<script>
|
1909 |
-
|
1910 |
-
|
1911 |
value:parseInt(<?php echo (int)$_CONFIG[cron_file_delete];?>),
|
1912 |
min: 0,
|
1913 |
max: 100,
|
1914 |
step: 1,
|
1915 |
slide: function( event, ui ) {
|
1916 |
-
|
1917 |
}
|
1918 |
});
|
1919 |
-
|
1920 |
});
|
1921 |
</script>
|
1922 |
|
@@ -2169,7 +2216,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2169 |
global $baDownloadPath, $mosConfig_absolute_path, $clonerPath, $task;
|
2170 |
|
2171 |
?>
|
2172 |
-
<form action="
|
2173 |
<script language="javascript" type="text/javascript">
|
2174 |
|
2175 |
|
@@ -2269,17 +2316,17 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2269 |
global $baDownloadPath, $mosConfig_absolute_path, $clonerPath, $_CONFIG, $database, $mosConfig_db;
|
2270 |
|
2271 |
?>
|
2272 |
-
<form action="
|
2273 |
<?php
|
2274 |
$tabs = new mosTabs(1);
|
2275 |
?>
|
2276 |
|
2277 |
<script>
|
2278 |
-
|
2279 |
-
|
2280 |
-
|
2281 |
-
|
2282 |
-
|
2283 |
});
|
2284 |
</script>
|
2285 |
|
@@ -2302,11 +2349,6 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2302 |
|
2303 |
<div id="radio_dbbackup">
|
2304 |
<table class="adminform">
|
2305 |
-
<!--<tr>
|
2306 |
-
<th colspan=2>
|
2307 |
-
<b><?php #echo LM_DATABASE_ARCHIVE; ?></b>
|
2308 |
-
</th>
|
2309 |
-
</tr>-->
|
2310 |
<tr>
|
2311 |
<td>
|
2312 |
<label for="radio_dbbackup1"><?php echo LM_CONFIRM_DATABASE; ?></label>
|
@@ -2332,8 +2374,8 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2332 |
<select name='excltables[]' MULTIPLE SIZE=15>
|
2333 |
<?php
|
2334 |
|
2335 |
-
$query =
|
2336 |
-
while($row =
|
2337 |
|
2338 |
echo "<option value='".$row[0]."'>$row[0]</option>";
|
2339 |
|
@@ -2353,9 +2395,9 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2353 |
<select name='databases_incl[]' MULTIPLE SIZE=5>
|
2354 |
<?php
|
2355 |
|
2356 |
-
$query =
|
2357 |
|
2358 |
-
while($row =
|
2359 |
|
2360 |
if($_CONFIG['mysql_database'] != $row[0])
|
2361 |
echo "<option value='".$row[0]."'>$row[0]</option>";
|
@@ -2404,9 +2446,9 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2404 |
{
|
2405 |
?>
|
2406 |
<tr><td>
|
2407 |
-
<link href="browser/filebrowser.css" rel="stylesheet" type="text/css">
|
2408 |
|
2409 |
-
<script type="text/javascript" src="browser/xmlhttp.js"></script>
|
2410 |
|
2411 |
|
2412 |
<div id="browser">
|
@@ -2478,7 +2520,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2478 |
<td><strong> </strong></td><td> </td>
|
2479 |
</tr>
|
2480 |
</table>
|
2481 |
-
<form action="
|
2482 |
<input type=hidden name=files[1] value='<?php echo $archiveName?>'>
|
2483 |
<input type=hidden name=cid[1] value='<?php echo $archiveName?>'>
|
2484 |
<input type="hidden" name="option" value="<?php echo $option; ?>"/>
|
@@ -2510,8 +2552,8 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2510 |
function showHelp( $option ) {
|
2511 |
?>
|
2512 |
<script>
|
2513 |
-
|
2514 |
-
|
2515 |
});
|
2516 |
</script>
|
2517 |
|
@@ -2526,7 +2568,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2526 |
</div>
|
2527 |
</div>
|
2528 |
</div>
|
2529 |
-
<form action="
|
2530 |
<input type="hidden" name="option" value="<?php echo $option; ?>"/>
|
2531 |
<input type="hidden" name="task" value=""/>
|
2532 |
</form>
|
@@ -2541,8 +2583,8 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2541 |
?>
|
2542 |
|
2543 |
<script>
|
2544 |
-
|
2545 |
-
|
2546 |
});
|
2547 |
</script>
|
2548 |
|
@@ -2560,7 +2602,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2560 |
</table>
|
2561 |
</p></div>
|
2562 |
</div>
|
2563 |
-
<form action="
|
2564 |
<input type="hidden" name="option" value="<?php echo $option; ?>"/>
|
2565 |
<input type="hidden" name="task" value=""/>
|
2566 |
</form>
|
@@ -2573,8 +2615,8 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2573 |
|
2574 |
?>
|
2575 |
<script>
|
2576 |
-
|
2577 |
-
|
2578 |
});
|
2579 |
</script>
|
2580 |
|
@@ -2592,7 +2634,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2592 |
</table>
|
2593 |
</p></div>
|
2594 |
</div>
|
2595 |
-
<form action="
|
2596 |
<input type="hidden" name="option" value="<?php echo $option; ?>"/>
|
2597 |
<input type="hidden" name="task" value=""/>
|
2598 |
</form>
|
@@ -2604,7 +2646,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2604 |
global $_CONFIG;
|
2605 |
|
2606 |
?>
|
2607 |
-
<form action="
|
2608 |
<table border="0" align="center" cellspacing="0" cellpadding="2" width="100%" class="adminform">
|
2609 |
<tr><th colspan='2'>
|
2610 |
<?php echo LM_RENAME_TOP?>
|
@@ -2624,7 +2666,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
|
|
2624 |
|
2625 |
?>
|
2626 |
</table>
|
2627 |
-
<form action="
|
2628 |
<input type="hidden" name="option" value="<?php echo $option; ?>"/>
|
2629 |
<input type="hidden" name="task" value="rename_save"/>
|
2630 |
</form>
|
24 |
/** ensure this file is being included by a parent file */
|
25 |
defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
|
26 |
|
|
|
|
|
|
|
27 |
class mosTabs{
|
28 |
|
29 |
function mosTabs($int){
|
63 |
global $mosConfig_live_site, $task;
|
64 |
$excl_tasks = array("view", "config","");
|
65 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
66 |
?>
|
67 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
<script type="text/javascript">
|
69 |
|
70 |
/* Optional: Temporarily hide the "tabber" class so it does not "flash"
|
74 |
document.write('<style type="text/css">.tabber{display:none;}<\/style>');
|
75 |
</script>
|
76 |
|
|
|
|
|
|
|
77 |
<table width='100%' style="padding-left: 3px; padding-right: 4px;align:center;" bgcolor='#ffffff'>
|
78 |
<tr><td align='right'>
|
79 |
|
86 |
<tr>
|
87 |
<td width='auto'>
|
88 |
<table><tr><td>
|
89 |
+
<img src="<?php echo plugins_url('images/backup.png', __FILE__) ?>" align="middle">
|
90 |
</td><td>
|
91 |
<a href="index.php"><h2><?php echo LM_COM_TITLE.$_SERVER['HTTP_HOST']; ?></h2>
|
92 |
<h1>Backup and Restore</h1>
|
121 |
|
122 |
d = new dTree('d');
|
123 |
|
124 |
+
d.add(0,-1,' <?php echo LM_MENU_CLONER;?>','plugins.php?page=xcloner_show&option=com_cloner','','','<?php echo plugins_url('images/logo.gif', __FILE__) ?>');
|
125 |
|
126 |
+
d.add(800,0,' <?php echo LM_MENU_ADMINISTRATION;?>','','','','<?php echo plugins_url('images/actions.gif', __FILE__) ?>','<?php echo plugins_url('images/actions.gif', __FILE__) ?>');
|
127 |
|
128 |
+
d.add(801,800,' <?php echo LM_MENU_CONFIGURATION;?>','plugins.php?page=xcloner_show&option=com_cloner&task=config','','','<?php echo plugins_url('images/gen_settings.png', __FILE__) ?>');
|
129 |
+
d.add(802,800,' <?php echo LM_MENU_CRON;?>','plugins.php?page=xcloner_show&option=com_cloner&task=cron','','','<?php echo plugins_url('images/templatessm.png', __FILE__) ?>');
|
130 |
+
d.add(803,800,' <?php echo LM_MENU_LANG;?>','plugins.php?page=xcloner_show&option=com_cloner&task=lang','','','<?php echo plugins_url('images/lang.png', __FILE__) ?>');
|
131 |
|
132 |
|
133 |
+
d.add(840,0,' <?php echo LM_MENU_ACTIONS;?>','','','','<?php echo plugins_url('images/actions.gif', __FILE__) ?>','<?php echo plugins_url('images/actions.gif', __FILE__) ?>');
|
134 |
+
d.add(841,840,' <?php echo LM_MENU_View_backups;?>','plugins.php?page=xcloner_show&option=com_cloner&task=view','','','<?php echo plugins_url('images/editionssm.png', __FILE__) ?>');
|
135 |
+
d.add(842,840,' <?php echo LM_MENU_Generate_backup;?>','plugins.php?page=xcloner_show&option=com_cloner&task=confirm','','','<?php echo plugins_url('images/wizardsm.png', __FILE__) ?>');
|
136 |
+
d.add(843,840,' <?php echo LM_MENU_Restore_backup;?>','plugins.php?page=xcloner_show&option=com_cloner&task=restore','','','<?php echo plugins_url('images/wizardsm_restore.png', __FILE__) ?>');
|
137 |
|
138 |
+
d.add(830,0,' <?php echo LM_MENU_SUPPORT;?>','','','','<?php echo plugins_url('images/support.png', __FILE__) ?>','<?php echo plugins_url('images/support.png', __FILE__) ?>');
|
139 |
+
d.add(831,830,' <?php echo LM_MENU_FORUM;?>','http://www.xcloner.com/support/forums/','','_blank','<?php echo plugins_url('images/forum.png', __FILE__) ?>','<?php echo plugins_url('images/forum.png', __FILE__) ?>');
|
140 |
+
d.add(832,830,' <?php echo LM_MENU_WEBSITE;?>','http://www.xcloner.com','','_blank','<?php echo plugins_url('images/website.png', __FILE__) ?>','<?php echo plugins_url('images/website.png', __FILE__) ?>');
|
141 |
|
142 |
|
143 |
|
144 |
+
d.add(820,0,' <?php echo LM_MENU_Documentation;?>','','','','<?php echo plugins_url('images/help.png', __FILE__) ?>','<?php echo plugins_url('images/gen_settings.png', __FILE__) ?>');
|
145 |
+
d.add(821,820,' <?php echo LM_MENU_ABOUT;?>','plugins.php?page=xcloner_show&option=com_cloner&task=about','','','<?php echo plugins_url('images/about.png', __FILE__) ?>','<?php echo plugins_url('images/about.png', __FILE__) ?>');
|
146 |
|
147 |
document.write(d);
|
148 |
|
149 |
//-->
|
150 |
</script></div> </td></tr></table>
|
151 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
152 |
|
153 |
</td><td valign='top' align='left' style="padding-left: 20px;">
|
154 |
|
169 |
<p>Powered by <a href='http://www.xcloner.com' target='_blank'>XCloner</a>. Backup and Restore Made Easy!</p></center>
|
170 |
|
171 |
</td></tr></table>
|
172 |
+
<script>
|
173 |
+
|
174 |
+
jQuery( "#toolbar" ).show();
|
175 |
+
|
176 |
+
</script>
|
177 |
+
|
178 |
|
179 |
<?php
|
180 |
|
191 |
echo "<h2>Initializing backup...</h2>";
|
192 |
echo "<h3 >Backup <b>$filename</b> created, we may continue!</h3><br />";
|
193 |
|
194 |
+
$urlReturn = "plugins.php?page=xcloner_show&option=com_cloner&lines=" . $perm_lines . "&task=refresh&backup=$backupFile&excl_manual=$excl_manual";
|
195 |
|
196 |
if(!$_CONFIG['refresh_mode']){
|
197 |
|
207 |
<!--Start ProgressBar-->
|
208 |
<script type="text/javascript">
|
209 |
|
210 |
+
jQuery(document).ready(function() {
|
211 |
|
212 |
var globalUrl;
|
213 |
var step = "r1";
|
219 |
var parts = 0;
|
220 |
var oldSize = 0;
|
221 |
|
222 |
+
jQuery("#progressbar").progressbar({ value: 0 });
|
223 |
|
224 |
+
jQuery.ajaxSetup({
|
225 |
"error":function(request, status, error) {
|
226 |
//reset state here;
|
227 |
+
jQuery("#error").show();
|
228 |
+
jQuery("#errorText").append(status+" -- "+error);
|
229 |
+
jQuery("#errorText").append("<br /><br />JSON url: "+globalUrl);
|
230 |
}});
|
231 |
|
232 |
function getSize(bytes, conv){
|
245 |
globalUrl = url;
|
246 |
step = "r1";
|
247 |
|
248 |
+
jQuery.getJSON(url, function(json) {
|
249 |
|
250 |
if(!json){
|
251 |
+
jQuery("#error").show();
|
252 |
+
jQuery("#errorText").text(url);
|
253 |
}
|
254 |
|
255 |
if(json.dumpsize && !json.endDump){
|
256 |
+
jQuery("#mysqlProcess").append(" ("+getSize(json.dumpsize, 1024*1024)+" MB) <br />");
|
257 |
}
|
258 |
|
259 |
if(json.newDump){
|
260 |
count++;
|
261 |
+
//jQuery("#mysqlProcess").append(appendIcon("arrowthick-1-e"));
|
262 |
if(json.databaseName!="")
|
263 |
+
jQuery("#mysqlProcess").append("<b>["+json.databaseName+"]</b> <span id='db"+count+"'></span> tables ");
|
264 |
counter = parseInt(json.startAtLine);
|
265 |
|
266 |
}else{
|
267 |
+
jQuery("#db"+count).text(json.startAtLine - counter);
|
268 |
}
|
269 |
|
270 |
if(!parseInt(json.finished)){
|
271 |
//get next records
|
272 |
|
273 |
+
jQuery("#db"+count).text(json.startAtLine - counter);
|
274 |
|
275 |
+
recurseUrl = "admin-ajax.php?action=json_return&task=recurse_database&nohtml=1&dbbackup_comp="+json.dbbackup_comp+"&dbbackup_drop="+json.dbbackup_drop+"&startAtLine="+json.startAtLine+"&startAtRecord="+json.startAtRecord+"&dumpfile="+json.dumpfile;
|
276 |
xclonerRecurseMYSQL(recurseUrl);
|
277 |
|
278 |
}
|
279 |
else{
|
280 |
|
281 |
+
jQuery("#fileSystem").show();
|
282 |
+
var recurseUrl="admin-ajax.php?action=json_return&task=recurse_files&mode=start&nohtml=1";
|
283 |
xclonerRecurseJSON(recurseUrl);
|
284 |
|
285 |
}
|
290 |
|
291 |
function xclonerRecurseJSON(url){
|
292 |
//scan file system
|
293 |
+
jQuery("#result").hide();
|
294 |
|
295 |
globalUrl = url;
|
296 |
step = "r2";
|
297 |
|
298 |
+
jQuery.getJSON(url, function(json) {
|
299 |
|
300 |
if(!json){
|
301 |
+
jQuery("#error").show();
|
302 |
+
jQuery("#errorText").text(url);
|
303 |
}
|
304 |
|
305 |
if(!parseInt(json.finished)){
|
306 |
|
307 |
+
jQuery("#recurseStatus").text(json.tfiles);
|
308 |
|
309 |
+
var recurseUrl = "admin-ajax.php?action=json_return&task=recurse_files&mode="+json.mode+"&nohtml=1&files="+json.tfiles;
|
310 |
xclonerRecurseJSON(recurseUrl);
|
311 |
|
312 |
}
|
313 |
else{
|
314 |
var size = parseFloat(json.size)/(1024*1024);
|
315 |
+
jQuery("#recurseStatus").text(" done! (Estimated size:"+size.toFixed(2)+"MB) in "+json.tfiles+" files");
|
316 |
+
jQuery("#result").show();
|
317 |
|
318 |
if(json.overlimit.length > 0){
|
319 |
+
jQuery("#overlimit").show();
|
320 |
for(var i=0; i < json.overlimit.length; i++){
|
321 |
|
322 |
+
jQuery("#overlimit").append("<span class='oversizedFile'></span>"+json.overlimit[i]+"<br />");
|
323 |
|
324 |
}
|
325 |
}
|
326 |
|
327 |
//xclonerGetJSON("<?php echo $urlReturn;?>");
|
328 |
+
returnUrl = "admin-ajax.php?action=json_return&option=com_cloner&lines="+json.tfiles+"&task=refresh&backup=<?php echo $backupFile; ?>&excl_manual=";
|
329 |
xclonerGetJSON(returnUrl);
|
330 |
|
331 |
}
|
339 |
globalUrl = url;
|
340 |
step = "r3";
|
341 |
|
342 |
+
jQuery.getJSON(url, function(json) {
|
343 |
|
344 |
if(!json){
|
345 |
+
jQuery("#error").show();
|
346 |
+
jQuery("#errorText").append(url);
|
347 |
}
|
348 |
|
349 |
var percent = parseInt(json.percent);
|
350 |
+
jQuery("#progressbar").progressbar({ value: percent });
|
351 |
+
jQuery("#backupSize").text(getSize(json.backupSize, 1024*1024));
|
352 |
+
jQuery("#nFiles").text(json.startf);
|
353 |
+
jQuery("#percent").text(json.percent);
|
354 |
+
jQuery("#backupName").text(json.backup);
|
355 |
if(!json.finished){
|
356 |
|
357 |
if(oldBackupName != json.backup){
|
362 |
oldSize = parseInt(json.backupSize);
|
363 |
}
|
364 |
|
365 |
+
var url = "admin-ajax.php?action=json_return&option="+json.option+"&task="+json.task+"&json="+json.json+"&startf="+json.startf+"&lines="+json.lines+"&backup="+json.backup+"&excl_manual="+json.excl_manual;
|
366 |
xclonerGetJSON(url);
|
367 |
}else{
|
368 |
|
369 |
//all done
|
370 |
+
url = "admin-ajax.php?action=json_return&task=cleanup&nohtml=1";
|
371 |
+
jQuery.getJSON(url, function(json) {
|
372 |
});
|
373 |
|
374 |
+
jQuery("#complete").show();
|
375 |
+
jQuery("#nFiles").text(json.lines);
|
376 |
if(parts > 0){
|
377 |
+
jQuery("#backupParts").show();
|
378 |
+
jQuery("#backupPartsNr").text(parts);
|
379 |
}
|
380 |
+
jQuery("#backupFiles").text(json.lines);
|
381 |
+
jQuery("#backupSizeComplete").append(getSize(completeSize+parseInt(json.backupSize), 1024*1024));
|
382 |
+
jQuery("#backupNameC").text(json.backup);
|
383 |
+
jQuery( "#dialog:ui-dialog" ).dialog( "destroy" );
|
384 |
+
jQuery( "#dialog-message" ).dialog({
|
385 |
modal: true,
|
386 |
width: 600,
|
387 |
buttons: {
|
388 |
Close: function() {
|
389 |
+
jQuery( this ).dialog( "close" );
|
390 |
}
|
391 |
}
|
392 |
});
|
399 |
|
400 |
//Main program here
|
401 |
|
402 |
+
jQuery("#retry").click(function(){
|
403 |
+
jQuery("#error").hide();
|
404 |
+
jQuery("#errorText").empty();
|
405 |
if(step == "r1"){
|
406 |
xclonerRecurseMYSQL(globalUrl);
|
407 |
}
|
414 |
}
|
415 |
});
|
416 |
|
417 |
+
jQuery("#result").hide();
|
418 |
+
jQuery("#fileSystem").hide();
|
419 |
|
420 |
if(dbbackup){
|
421 |
+
recurseUrl = "admin-ajax.php?action=json_return&task=recurse_database&nohtml=1&dbbackup_comp=<?php echo $_REQUEST['dbbackup_comp']?>&dbbackup_drop=<?php echo $_REQUEST['dbbackup_drop']?>";
|
422 |
xclonerRecurseMYSQL(recurseUrl);
|
423 |
}else{
|
424 |
+
jQuery("#fileSystem").show();
|
425 |
+
var recurseUrl="admin-ajax.php?action=json_return&task=recurse_files&mode=start&nohtml=1";
|
426 |
xclonerRecurseJSON(recurseUrl);
|
427 |
|
428 |
}
|
463 |
<div id="complete">
|
464 |
<br /><h2>Backup completed!</h2>
|
465 |
|
466 |
+
<form action="" name="adminForm" method="post">
|
467 |
<input type=hidden name=files[1] value='<?php echo $backupFile?>'>
|
468 |
<input type=hidden name=cid[1] value='<?php echo $backupFile?>'>
|
469 |
<input type="hidden" name="option" value="<?php echo $option; ?>"/>
|
535 |
}
|
536 |
|
537 |
function _FDefault(){
|
538 |
+
global $_CONFIG, $html;
|
539 |
?>
|
540 |
|
541 |
+
<form action="" method="post" name="adminForm">
|
542 |
|
543 |
<table class="adminform">
|
544 |
<tr><th valign='top' >
|
553 |
<div style="float:left;">
|
554 |
<div class="icon">
|
555 |
|
556 |
+
<a href="plugins.php?page=xcloner_show&option=com_cloner&task=config">
|
557 |
+
<img src="<?php echo plugins_url('images/settings.png', __FILE__) ?>"
|
558 |
alt="Settings" align="middle" name="" border="0" />
|
559 |
<span><?php echo LM_MAIN_Settings?></span>
|
560 |
</a>
|
564 |
<div style="float:left;">
|
565 |
<div class="icon">
|
566 |
|
567 |
+
<a href="plugins.php?page=xcloner_show&option=com_cloner&task=view">
|
568 |
+
<img src="<?php echo plugins_url('images/editions.png', __FILE__) ?>"
|
569 |
alt="View Backups" align="middle" name="" border="0" />
|
570 |
<span><?php echo LM_MAIN_View_Backups?></span>
|
571 |
</a>
|
575 |
<div style="float:left;">
|
576 |
<div class="icon">
|
577 |
|
578 |
+
<a href="plugins.php?page=xcloner_show&option=com_cloner&task=confirm">
|
579 |
+
<img src="<?php echo plugins_url('images/wizard.png', __FILE__) ?>"
|
580 |
alt="MagaGenerate Backup" align="middle" name="" border="0" />
|
581 |
<span><?php echo LM_MAIN_Generate_Backup?></span>
|
582 |
</a>
|
586 |
<div style="float:left;">
|
587 |
<div class="icon">
|
588 |
|
589 |
+
<a href="plugins.php?page=xcloner_show&option=com_cloner&task=about">
|
590 |
+
<img src="<?php echo plugins_url('images/lhelp.png', __FILE__) ?>"
|
591 |
alt="MagaGenerate Backup" align="middle" name="" border="0" />
|
592 |
<span><?php echo LM_MAIN_Help?></span>
|
593 |
</a>
|
610 |
<div class="status">
|
611 |
<span class="mtext">Backup Start Path Check: </span>
|
612 |
<?php
|
613 |
+
$html = new HTML_cloner();
|
614 |
+
$stat = $html->path_check($_CONFIG[backup_start_path]);
|
615 |
|
616 |
if( $stat['code'] > 0 and $stat['code'] < 3){
|
617 |
echo "<span class='error'>".$stat['message']; $error = 1;
|
618 |
}
|
619 |
else{
|
620 |
echo "<span class='success'>OK";
|
621 |
+
if(!is_dir($_CONFIG[backup_start_path]."/administrator/backups")){
|
622 |
+
@mkdir($_CONFIG[backup_start_path]."/administrator");
|
623 |
+
if(@mkdir($_CONFIG[backup_start_path]."/administrator/backups"))
|
624 |
+
echo "<script>window.location='plugins.php?page=xcloner_show'</script";
|
625 |
+
}
|
626 |
+
}
|
627 |
echo " ($_CONFIG[backup_start_path])";
|
628 |
?>
|
629 |
</span></div>
|
632 |
<span class="mtext">Backup Store Path Check: </span>
|
633 |
<?php
|
634 |
|
635 |
+
$stat = $html->path_check($_CONFIG[backup_store_path]);
|
636 |
|
637 |
if( $stat['code'] > 0){
|
638 |
echo "<span class='error'>".$stat['message']; $error = 1;
|
649 |
<span class="mtext">Temporary Path Check: </span>
|
650 |
<?php
|
651 |
|
652 |
+
$stat = $html->path_check($_CONFIG[temp_dir]);
|
653 |
|
654 |
if( $stat['code'] > 0){
|
655 |
echo "<span class='error'>".$stat['message']; $error = 1;
|
661 |
?>
|
662 |
</span></div>
|
663 |
|
664 |
+
<!--<div class="status">
|
665 |
<span class="mtext">Authentication: </span>
|
666 |
<?php
|
667 |
|
668 |
if($_CONFIG['jcpass'] == md5('admin')){
|
669 |
+
#echo "<span class='error'>Change default password 'admin'"; $error = 1;
|
670 |
}
|
671 |
else{
|
672 |
+
#echo "<span class='success'>OK";
|
673 |
}
|
674 |
|
675 |
?>
|
676 |
+
</span></div>-->
|
677 |
|
678 |
<div class="status">
|
679 |
<span class="mtext">Backup Ready: </span>
|
706 |
<center><br />
|
707 |
|
708 |
<script>
|
709 |
+
jQuery(function() {
|
710 |
+
jQuery( "#login" ).button({
|
711 |
icons: {
|
712 |
primary: "ui-icon-locked"
|
713 |
}
|
714 |
+
})
|
715 |
+
jQuery("#login").click(function() {
|
716 |
+
jQuery("#adminForm")[0].submit();
|
717 |
+
return false;
|
718 |
+
})
|
719 |
+
|
720 |
+
jQuery( "#reset" ).button({
|
721 |
icons: {
|
722 |
primary: "ui-icon-trash"
|
723 |
}
|
724 |
})
|
725 |
+
jQuery( "#reset" ).click(function() {
|
726 |
+
jQuery("#username").val('');jQuery("#password").val('');
|
727 |
+
return false;
|
728 |
+
});
|
|
|
729 |
|
730 |
});
|
731 |
</script>
|
732 |
|
733 |
|
734 |
<div class="loginform">
|
735 |
+
<form action="" method="post" name="adminForm" id="adminForm">
|
736 |
<table class="loginForm">
|
737 |
<tr><td align='center'>
|
738 |
<table align='center' cellpadding='10' cellspacing='20'>
|
739 |
<tr ><td colspan='2' align='center'><b>Authentication Area:</b></td></tr>
|
740 |
+
<tr><td>Username:</td><td><input type='text' size='30' name='username' id='username'></td></tr>
|
741 |
+
<tr><td>Password:</td><td><input type='password' size='30' name='password' id='password'></td></tr>
|
742 |
<tr><td> </td><td>
|
743 |
<div class="loginform">
|
744 |
+
<button id="login">Login</button>
|
745 |
+
<button id="reset">Reset</button>
|
746 |
|
747 |
|
748 |
</div>
|
768 |
?>
|
769 |
|
770 |
<script>
|
771 |
+
jQuery(function() {
|
772 |
+
jQuery( "#tabs" ).tabs();
|
773 |
});
|
774 |
</script>
|
775 |
|
785 |
<br /><br />
|
786 |
|
787 |
<ul>
|
788 |
+
<li><input type="text" value="/usr/bin/php <?php echo dirname(__FILE__);?>/cloner.cron.php custom_cron_config.php" size="150" /></li>
|
|
|
|
|
|
|
789 |
</ul>
|
790 |
<br /><br />
|
791 |
|
792 |
For <b>Running Multiple Crons</b>, you need to first create a custom configuration file in the XCloner Configuration -> Cron tab
|
793 |
+
and then replace "cloner.cron.php" with "cloner.cron.php myconfig.php"
|
|
|
|
|
|
|
|
|
794 |
<br /><br />
|
795 |
|
796 |
<?php echo LM_CRON_HELP?>
|
806 |
function Translator_Edit_DEFAULT($option, $content, $file, $lang){
|
807 |
global $_CONFIG;
|
808 |
?>
|
809 |
+
<form action="" method="post" name="adminForm">
|
810 |
<table class="adminlist">
|
811 |
<tr>
|
812 |
<th align="left"><?php echo LM_LANG_EDIT_FILE?> <?php echo $file?></th>
|
832 |
function Translator_Add($option){
|
833 |
global $_CONFIG;
|
834 |
?>
|
835 |
+
<form action="" method="post" name="adminForm">
|
836 |
<table class="adminlist">
|
837 |
<tr>
|
838 |
<th align="left"><?php echo LM_LANG_NEW?></th>
|
857 |
global $_CONFIG;
|
858 |
?>
|
859 |
|
860 |
+
<form action="" method="post" name="adminForm">
|
861 |
<table class="adminlist">
|
862 |
<tr>
|
863 |
<th align="left"><?php echo LM_LANG_EDIT_FILE?> <input type=text name='lfile' size=100 value='<?php echo $file?>'><br />
|
932 |
|
933 |
?>
|
934 |
<script>
|
935 |
+
jQuery(function() {
|
936 |
+
jQuery( "#toggle" ).button();
|
937 |
+
jQuery( "#toggle" ).click(function() { checkJAll(<?php echo count( $lang_arr ); ?>, "toggle", "cb"); });
|
938 |
+
jQuery( "#checklist" ).buttonset();
|
939 |
});
|
940 |
</script>
|
941 |
|
942 |
+
<form action="" method="post" name="adminForm">
|
943 |
<div id="checklist">
|
944 |
<table class="adminlist">
|
945 |
<tr>
|
964 |
<input type="hidden" name="files[<?php echo $i?>]" value="<?php echo $lang_arr[$i] ?>" />
|
965 |
</td>
|
966 |
<td align="left" >
|
967 |
+
<a href="plugins.php?page=xcloner_show&option=<?php echo $option;?>&task=edit_lang&langx=<?php echo $lang_arr[$i];?>"><?php echo ucfirst($lang_arr[$i])?>
|
968 |
</td>
|
969 |
</tr>
|
970 |
<?php
|
988 |
|
989 |
?>
|
990 |
|
991 |
+
<script type="text/javascript">
|
992 |
+
|
993 |
+
jQuery(function() {
|
994 |
+
jQuery( "#toggle" ).button();
|
995 |
+
jQuery( "#toggle" ).click(function() { checkJAll(<?php echo (count( $files )); ?>, "toggle", "cb"); });
|
996 |
+
jQuery( "#checklist" ).buttonset();
|
997 |
+
|
998 |
+
jQuery( "#Clone, #Rename, #Delete, #Move" ).unbind("click");
|
999 |
+
jQuery( "#Clone, #Rename, #Delete, #Move" ).click(function(){
|
1000 |
+
if(!jQuery("input:checked").length){
|
1001 |
+
|
1002 |
+
jQuery( "#error-message" ).dialog({
|
1003 |
+
width: 500,
|
1004 |
+
height: 200,
|
1005 |
+
modal: true,
|
1006 |
+
buttons: {
|
1007 |
+
Ok: function() {
|
1008 |
+
jQuery( this ).dialog( "close" );
|
1009 |
+
}
|
1010 |
+
}
|
1011 |
+
});
|
1012 |
+
|
1013 |
+
return false;
|
1014 |
+
}else{
|
1015 |
+
var action = jQuery(this).attr('id').toLowerCase();
|
1016 |
+
document.adminForm.task.value=action;
|
1017 |
+
document.adminForm.submit();
|
1018 |
+
}
|
1019 |
+
})
|
1020 |
+
|
1021 |
+
|
1022 |
+
})
|
1023 |
</script>
|
1024 |
+
|
1025 |
+
<div id="error-message" title="Error" style="display:none;">
|
1026 |
+
<p>
|
1027 |
+
<span class="ui-icon ui-icon-circle-check" style="float:left; margin:0 7px 50px 0;"></span>
|
1028 |
+
Please select at least one backup archive.
|
1029 |
+
</p>
|
1030 |
+
|
1031 |
+
</div>
|
1032 |
<div id="checklist">
|
1033 |
+
<form action="" method="post" name="adminForm">
|
1034 |
<table class="adminlist">
|
1035 |
<tr>
|
1036 |
<th width="100">
|
1053 |
$k = 0;
|
1054 |
for ($i=0; $i <= (count( $files )-1); $i++) {
|
1055 |
$date = date ("D jS M Y H:i:s (\G\M\T O)", filemtime($path.'/'.$files[$i]));
|
1056 |
+
$url = "admin-ajax.php?action=json_return&page=xcloner_show&option=com_cloner&task=download&file=".'/'.urlencode($files[$i]);
|
1057 |
?>
|
1058 |
<tr class="<?php echo "row$k"; ?>">
|
1059 |
|
1063 |
<input type="hidden" name="files[<?php echo $i?>]" value="<?php echo $files[$i] ?>" />
|
1064 |
</td>
|
1065 |
<td align="left">
|
1066 |
+
<a target='_blank' href="<?php echo $url ?>"><img src="<?php echo plugins_url('images/filesave.png', __FILE__) ?>" border="0" title="<?php echo LM_DOWNLOAD_TITLE." - ".$files[$i] ?>" /></a>
|
1067 |
</td>
|
1068 |
<td>
|
1069 |
<span class="backup_name"><?php echo $files[$i]; ?></span>
|
1095 |
function Config($option){
|
1096 |
global $config_file,$_CONFIG, $lang_array, $database, $mosConfig_db;
|
1097 |
?>
|
1098 |
+
<form name='adminForm' action='' method='POST'>
|
1099 |
|
1100 |
<script>
|
1101 |
+
jQuery(function() {
|
1102 |
+
jQuery( "#tabs" ).tabs();
|
1103 |
});
|
1104 |
|
1105 |
+
jQuery(function() {
|
1106 |
+
jQuery( "#radiog1" ).buttonset();
|
1107 |
+
jQuery( "#radiog2" ).buttonset();
|
1108 |
+
jQuery( "#radiog3" ).buttonset();
|
1109 |
+
jQuery( "#radiog4" ).buttonset();
|
1110 |
+
jQuery( "#radio" ).buttonset();
|
1111 |
+
jQuery( "#radiom" ).buttonset();
|
1112 |
+
jQuery( "#radiob" ).buttonset();
|
1113 |
+
jQuery( "#radioftp" ).buttonset();
|
1114 |
+
jQuery( "#radioftps" ).buttonset();
|
1115 |
+
jQuery( "#radiodebug" ).buttonset();
|
1116 |
+
jQuery( "#radiorefresh" ).buttonset();
|
1117 |
+
jQuery( "#checktar" ).button();
|
1118 |
+
jQuery( "#cron_file_delete_act" ).button();
|
1119 |
+
jQuery( "#cron_sql_drop" ).button();
|
1120 |
+
jQuery( "#cron_amazon_active" ).button();
|
1121 |
+
jQuery( "#cron_dropbox_active" ).button();
|
1122 |
+
jQuery( "#cron_amazon_ssl" ).button();
|
1123 |
+
jQuery( "#cron_ftp_delb" ).button();
|
1124 |
+
jQuery( "#checkmysqldump" ).button();
|
1125 |
});
|
1126 |
</script>
|
1127 |
|
1130 |
|
1131 |
<li><a href="#tabs-1"><?php echo LM_TAB_GENERAL;?></a></li>
|
1132 |
<li><a href="#tabs-2"><?php echo LM_TAB_MYSQL;?></a></li>
|
1133 |
+
<!--<li><a href="#tabs-3"><?php echo LM_TAB_AUTH;?></a></li>-->
|
1134 |
<li><a href="#tabs-4"><?php echo LM_TAB_SYSTEM;?></a></li>
|
1135 |
<li><a href="#tabs-5"><?php echo LM_TAB_CRON;?></a></li>
|
1136 |
<li><a href="#tabs-6"><?php echo LM_TAB_INFO;?></a></li>
|
1137 |
</ul>
|
1138 |
|
1139 |
<table class='adminform'>
|
1140 |
+
<!--<tr><th colspan='2'>
|
1141 |
+
<?php #echo LM_CONFIG_EDIT?> <?php #echo $config_file?>
|
1142 |
+
</th></tr>-->
|
1143 |
</table>
|
1144 |
<?php
|
1145 |
$tabs->startTab(LM_TAB_GENERAL,"1");
|
1194 |
</td>
|
1195 |
</tr>
|
1196 |
|
1197 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1198 |
|
1199 |
<tr>
|
1200 |
<td>
|
1202 |
</td>
|
1203 |
<td>
|
1204 |
<div id="radiog3">
|
1205 |
+
<label for="radiog31">Yes</label> <input id="radiog31" type=radio size=50 value=1 name='enable_db_backup' <?php if($_CONFIG[enable_db_backup]==1 or $_CONFIG['disable_mysql']) echo 'checked';?>>
|
1206 |
+
<label for="radiog32">No</label> <input id="radiog32" type=radio size=50 value=0 name='enable_db_backup' <?php if($_CONFIG[enable_db_backup]==0 and !$_CONFIG['disable_mysql']) echo 'checked';?>>
|
1207 |
<br /><?php echo LM_CRON_DB_BACKUP_SUB?>
|
1208 |
</div>
|
1209 |
|
1236 |
<?php echo LM_CONFIG_MEM?>
|
1237 |
</td>
|
1238 |
<td align='left'>
|
1239 |
+
<table style="width:auto; margin-bottom: 10px;" cellpadding='0' cellspacing='2' border='0'>
|
1240 |
<tr bgcolor='#efefef'><td style="width:70px;">
|
1241 |
<label for="checktar"><?php echo LM_ACTIVE;?></label> <input type=checkbox id="checktar" value=1 name='mem' <?php if($_CONFIG[mem]==1) echo 'checked';?>>
|
1242 |
</td><td align='left'>
|
1268 |
</p></div>
|
1269 |
</div>
|
1270 |
|
1271 |
+
<!--<div>
|
1272 |
<h3><a href="#">Public Key Management</a></h3>
|
1273 |
<div><p>
|
1274 |
<table class='adminForm'>
|
1286 |
|
1287 |
</table>
|
1288 |
</p></div>
|
1289 |
+
</div>-->
|
1290 |
|
1291 |
</div>
|
1292 |
|
1360 |
</div>
|
1361 |
<?php
|
1362 |
$tabs->endTab();
|
1363 |
+
/*$tabs->startTab(LM_TAB_AUTH,"3");
|
1364 |
?>
|
1365 |
<div id="configtabinside">
|
1366 |
<div>
|
1391 |
</div>
|
1392 |
</div>
|
1393 |
<?php
|
1394 |
+
$tabs->endTab();*/
|
1395 |
$tabs->startTab(LM_TAB_SYSTEM,"4");
|
1396 |
?>
|
1397 |
|
1443 |
</td><td>
|
1444 |
<div id="radioftps">
|
1445 |
<label for="radioftps1">Normal</label><input id="radioftps1" type=radio size=50 value=0 name='secure_ftp' <?php if($_CONFIG[secure_ftp]==0) echo 'checked';?>>
|
1446 |
+
<label for="radioftps2">Secure(SFTP)</label><input id="radioftps2" type=radio size=50 value=1 name='secure_ftp' <?php if($_CONFIG[secure_ftp]==1) echo 'checked';?>>
|
1447 |
</td>
|
1448 |
</tr>
|
1449 |
|
1455 |
<div><p>
|
1456 |
|
1457 |
<script>
|
1458 |
+
jQuery(function() {
|
1459 |
+
jQuery( "#slider" ).slider({
|
1460 |
value:parseInt(<?php echo $_CONFIG[backup_refresh_number];?>),
|
1461 |
min: 10,
|
1462 |
max: 1000,
|
1463 |
step: 10,
|
1464 |
slide: function( event, ui ) {
|
1465 |
+
jQuery( "#backup_refresh_number" ).val( ui.value );
|
1466 |
}
|
1467 |
});
|
1468 |
+
jQuery( "#backup_refresh_number" ).val( jQuery( "#slider" ).slider( "value" ) );
|
1469 |
});
|
1470 |
+
jQuery(function() {
|
1471 |
+
jQuery( "#sliderRPS" ).slider({
|
1472 |
value:parseInt(<?php echo $_CONFIG[recordsPerSession];?>),
|
1473 |
min: 100,
|
1474 |
max: 100000,
|
1475 |
step: 100,
|
1476 |
slide: function( event, ui ) {
|
1477 |
+
jQuery( "#recordsPerSession" ).val( ui.value );
|
1478 |
}
|
1479 |
});
|
1480 |
+
jQuery( "#recordsPerSession" ).val( jQuery( "#sliderRPS" ).slider( "value" ) );
|
1481 |
});
|
1482 |
+
jQuery(function() {
|
1483 |
+
jQuery( "#sliderEFZ" ).slider({
|
1484 |
value:parseInt(<?php echo $_CONFIG[excludeFilesSize];?>),
|
1485 |
min: -1,
|
1486 |
max: 10240,
|
1487 |
step: 1,
|
1488 |
slide: function( event, ui ) {
|
1489 |
+
jQuery( "#excludeFilesSize" ).val( ui.value );
|
1490 |
}
|
1491 |
});
|
1492 |
+
jQuery( "#excludeFilesSize" ).val( jQuery( "#sliderEFZ" ).slider( "value" ) );
|
1493 |
});
|
1494 |
|
1495 |
+
jQuery(function() {
|
1496 |
+
jQuery( "#sliderSBS" ).slider({
|
1497 |
value:parseInt(<?php echo $_CONFIG[splitBackupSize];?>),
|
1498 |
min: -1,
|
1499 |
max: 10000,
|
1500 |
step: 1,
|
1501 |
slide: function( event, ui ) {
|
1502 |
+
jQuery( "#splitBackupSize" ).val( ui.value );
|
1503 |
}
|
1504 |
});
|
1505 |
+
jQuery( "#splitBackupSize" ).val( jQuery( "#sliderSBS" ).slider( "value" ) );
|
1506 |
});
|
1507 |
</script>
|
1508 |
|
1555 |
<input type=text size=20 name='refresh_time' value=<?php echo $_CONFIG[refresh_time];?>> miliseconds
|
1556 |
|
1557 |
</td></tr>
|
1558 |
+
|
1559 |
+
<tr>
|
1560 |
+
<td>
|
1561 |
+
<?php echo LM_CRON_COMPRESS?>
|
1562 |
+
</td>
|
1563 |
+
<td>
|
1564 |
+
<div id="radiog2">
|
1565 |
+
<label for="radiog21"><?php echo LM_YES?></label> <input id="radiog21" type=radio size=50 value=1 name='backup_compress' <?php if($_CONFIG[backup_compress]==1) echo 'checked';?>>
|
1566 |
+
<label for="radiog22"><?php echo LM_NO?></label> <input id="radiog22" type=radio size=50 value=0 name='backup_compress' <?php if($_CONFIG[backup_compress]==0) echo 'checked';?>>
|
1567 |
+
<br /> <small>Note: this option might break your backup process if the Manual backup option is also enabled</small>
|
1568 |
+
</div>
|
1569 |
+
</td>
|
1570 |
+
</tr>
|
1571 |
|
1572 |
<tr><td>
|
1573 |
<?php echo LM_REFRESH_MODE?>
|
1618 |
</td>
|
1619 |
<td>
|
1620 |
<?php
|
1621 |
+
|
1622 |
+
if ($handle = opendir($_CONFIG['multiple_config_dir'])) {
|
1623 |
|
1624 |
while (false !== ($file = readdir($handle))) {
|
1625 |
if( ($file!=".") && ($file!="..") &&($file!="") && (strstr($file, '.php'))){
|
1626 |
+
$fcron = plugins_url('cloner.cron.php', __FILE__)."?config=$file";
|
1627 |
|
1628 |
echo "<b>$fcron</b>";
|
1629 |
|
1630 |
echo " - <a href='$fcron' target='_blank'>execute cron</a>";
|
1631 |
|
1632 |
+
echo " | <a href='plugins.php?page=xcloner_show&option=com_cloner&task=cron_delete&fconfig=$file'>delete config</a>";
|
1633 |
|
1634 |
echo "\n<br />";
|
1635 |
}
|
1706 |
</tr>
|
1707 |
|
1708 |
|
1709 |
+
<!-- <tr>
|
1710 |
<td>
|
1711 |
<?php echo LM_CRON_IP?>
|
1712 |
</td>
|
1714 |
<textarea type=text size=50 name='cron_ip' cols='30' rows='5'><?php echo $_CONFIG[cron_ip]?></textarea> <br />
|
1715 |
<?php echo LM_CRON_IP_SUB?>
|
1716 |
</td>
|
1717 |
+
</tr>-->
|
1718 |
</table>
|
1719 |
</p></div>
|
1720 |
</div>
|
1781 |
<td>
|
1782 |
<label for="cron_amazon_active"><?php echo LM_AMAZON_S3_ACTIVATE?></label>
|
1783 |
<input id="cron_amazon_active" type=checkbox name='cron_amazon_active' <?php if($_CONFIG[cron_amazon_active]==1) echo "checked";?> value='1'>
|
1784 |
+
|
1785 |
+
<label for="cron_amazon_ssl"><?php echo LM_AMAZON_S3_SSL?></label>
|
1786 |
+
<input id="cron_amazon_ssl" type=checkbox name='cron_amazon_ssl' <?php if($_CONFIG[cron_amazon_ssl]==1) echo "checked";?> value='1'>
|
1787 |
</td>
|
1788 |
</tr>
|
1789 |
|
1804 |
<input type=text size=50 name='cron_amazon_awsSecretKey' value="<?php echo $_CONFIG['cron_amazon_awsSecretKey'];?>">
|
1805 |
</td>
|
1806 |
</tr>
|
1807 |
+
|
1808 |
<tr>
|
1809 |
<td width='200'>
|
1810 |
<?php echo LM_AMAZON_S3_BUCKET;?>
|
1827 |
</p></div>
|
1828 |
</div>
|
1829 |
|
1830 |
+
<div>
|
1831 |
+
<h3><a href="#"> <?php echo LM_DROPBOX?></a></h3>
|
1832 |
+
<div><p>
|
1833 |
+
<table class='adminform'>
|
1834 |
+
|
1835 |
+
<tr>
|
1836 |
+
<td width='250'>
|
1837 |
+
<?php #echo LM_AMAZON_S3_ACTIVATE?>
|
1838 |
+
</td>
|
1839 |
+
<td>
|
1840 |
+
<label for="cron_dropbox_active"><?php echo LM_DROPBOX_ACTIVATE?></label>
|
1841 |
+
<input id="cron_dropbox_active" type=checkbox name='cron_dropbox_active' <?php if($_CONFIG[cron_dropbox_active]==1) echo "checked";?> value='1'>
|
1842 |
+
|
1843 |
+
|
1844 |
+
</td>
|
1845 |
+
</tr>
|
1846 |
+
|
1847 |
+
<tr>
|
1848 |
+
<td>
|
1849 |
+
<?php echo LM_DROPBOX_AWSACCESSKEY;?>
|
1850 |
+
</td>
|
1851 |
+
<td>
|
1852 |
+
<input type=text size=50 name='cron_dropbox_Key' value="<?php echo $_CONFIG['cron_dropbox_Key'];?>">
|
1853 |
+
</td>
|
1854 |
+
</tr>
|
1855 |
+
|
1856 |
+
<tr>
|
1857 |
+
<td>
|
1858 |
+
<?php echo LM_DROPBOX_AWSSECRETKEY;?>
|
1859 |
+
</td>
|
1860 |
+
<td>
|
1861 |
+
<input type=text size=50 name='cron_dropbox_Secret' value="<?php echo $_CONFIG['cron_dropbox_Secret'];?>">
|
1862 |
+
</td>
|
1863 |
+
</tr>
|
1864 |
+
|
1865 |
+
<tr>
|
1866 |
+
<td>
|
1867 |
+
<?php echo LM_DROPBOX_DIRNAME;?>
|
1868 |
+
</td>
|
1869 |
+
<td>
|
1870 |
+
<input type=text size=50 name='cron_dropbox_dirname' value="<?php echo $_CONFIG['cron_dropbox_dirname'];?>">
|
1871 |
+
</td>
|
1872 |
+
</tr>
|
1873 |
+
</tr>
|
1874 |
+
|
1875 |
+
</tr>
|
1876 |
+
</table>
|
1877 |
+
</p></div>
|
1878 |
+
</div>
|
1879 |
+
|
1880 |
<div>
|
1881 |
<h3><a href="#"> <?php echo LM_CRON_EMAIL_DETAILS?></a></h3>
|
1882 |
<div><p>
|
1910 |
</tr>
|
1911 |
|
1912 |
<?php
|
1913 |
+
if((abs($_CONFIG['system_mdatabases'])==0) && ($_CONFIG['enable_db_backup']==1) ){
|
1914 |
?>
|
1915 |
<tr><td valign='top'>
|
1916 |
<?php echo LM_DATABASE_INCLUDE_DATABASES?>
|
1920 |
|
1921 |
$curent_dbs = explode(",", $_CONFIG['databases_incl_list']);
|
1922 |
|
1923 |
+
$query = @$_CONFIG['mysqli']->query("SHOW databases");
|
1924 |
+
while($row = @$query->fetch_array()){
|
1925 |
|
1926 |
$table = $row[0];
|
1927 |
|
1953 |
<div><p>
|
1954 |
|
1955 |
<script>
|
1956 |
+
jQuery(function() {
|
1957 |
+
jQuery( "#slider2" ).slider({
|
1958 |
value:parseInt(<?php echo (int)$_CONFIG[cron_file_delete];?>),
|
1959 |
min: 0,
|
1960 |
max: 100,
|
1961 |
step: 1,
|
1962 |
slide: function( event, ui ) {
|
1963 |
+
jQuery( "#cron_file_delete" ).val( ui.value );
|
1964 |
}
|
1965 |
});
|
1966 |
+
jQuery( "#cron_file_delete" ).val( jQuery( "#slider2" ).slider( "value" ) );
|
1967 |
});
|
1968 |
</script>
|
1969 |
|
2216 |
global $baDownloadPath, $mosConfig_absolute_path, $clonerPath, $task;
|
2217 |
|
2218 |
?>
|
2219 |
+
<form action="" method="POST" name="adminForm">
|
2220 |
<script language="javascript" type="text/javascript">
|
2221 |
|
2222 |
|
2316 |
global $baDownloadPath, $mosConfig_absolute_path, $clonerPath, $_CONFIG, $database, $mosConfig_db;
|
2317 |
|
2318 |
?>
|
2319 |
+
<form action="" method="post" name="adminForm">
|
2320 |
<?php
|
2321 |
$tabs = new mosTabs(1);
|
2322 |
?>
|
2323 |
|
2324 |
<script>
|
2325 |
+
jQuery(function() {
|
2326 |
+
jQuery( "#tabs" ).tabs().find( ".ui-tabs-nav" ).sortable({ axis: "x" });
|
2327 |
+
jQuery( "#radio_dbbackup" ).buttonset();
|
2328 |
+
jQuery( "#radio_dbbackup1" ).button( { icons: {primary:'ui-icon-bullet'} } );
|
2329 |
+
jQuery( "#radio_dbbackup2" ).button( { icons: {primary:'ui-icon-bullet'} } );
|
2330 |
});
|
2331 |
</script>
|
2332 |
|
2349 |
|
2350 |
<div id="radio_dbbackup">
|
2351 |
<table class="adminform">
|
|
|
|
|
|
|
|
|
|
|
2352 |
<tr>
|
2353 |
<td>
|
2354 |
<label for="radio_dbbackup1"><?php echo LM_CONFIRM_DATABASE; ?></label>
|
2374 |
<select name='excltables[]' MULTIPLE SIZE=15>
|
2375 |
<?php
|
2376 |
|
2377 |
+
$query = $_CONFIG['mysqli']->query("SHOW tables");
|
2378 |
+
while($row = $query->fetch_array()){
|
2379 |
|
2380 |
echo "<option value='".$row[0]."'>$row[0]</option>";
|
2381 |
|
2395 |
<select name='databases_incl[]' MULTIPLE SIZE=5>
|
2396 |
<?php
|
2397 |
|
2398 |
+
$query = $_CONFIG['mysqli']->query("SHOW databases");
|
2399 |
|
2400 |
+
while($row = $query->fetch_array()){
|
2401 |
|
2402 |
if($_CONFIG['mysql_database'] != $row[0])
|
2403 |
echo "<option value='".$row[0]."'>$row[0]</option>";
|
2446 |
{
|
2447 |
?>
|
2448 |
<tr><td>
|
2449 |
+
<link href="<?php echo plugins_url('browser/filebrowser.css', __FILE__) ?>" rel="stylesheet" type="text/css">
|
2450 |
|
2451 |
+
<script type="text/javascript" src="<?php echo plugins_url('browser/xmlhttp.js', __FILE__) ?>"></script>
|
2452 |
|
2453 |
|
2454 |
<div id="browser">
|
2520 |
<td><strong> </strong></td><td> </td>
|
2521 |
</tr>
|
2522 |
</table>
|
2523 |
+
<form action="" name="adminForm" method="post">
|
2524 |
<input type=hidden name=files[1] value='<?php echo $archiveName?>'>
|
2525 |
<input type=hidden name=cid[1] value='<?php echo $archiveName?>'>
|
2526 |
<input type="hidden" name="option" value="<?php echo $option; ?>"/>
|
2552 |
function showHelp( $option ) {
|
2553 |
?>
|
2554 |
<script>
|
2555 |
+
jQuery(function() {
|
2556 |
+
jQuery( "#tabs" ).tabs();
|
2557 |
});
|
2558 |
</script>
|
2559 |
|
2568 |
</div>
|
2569 |
</div>
|
2570 |
</div>
|
2571 |
+
<form action="" name="adminForm" method="post">
|
2572 |
<input type="hidden" name="option" value="<?php echo $option; ?>"/>
|
2573 |
<input type="hidden" name="task" value=""/>
|
2574 |
</form>
|
2583 |
?>
|
2584 |
|
2585 |
<script>
|
2586 |
+
jQuery(function() {
|
2587 |
+
jQuery( "#tabs" ).tabs();
|
2588 |
});
|
2589 |
</script>
|
2590 |
|
2602 |
</table>
|
2603 |
</p></div>
|
2604 |
</div>
|
2605 |
+
<form action="" name="adminForm" method="post">
|
2606 |
<input type="hidden" name="option" value="<?php echo $option; ?>"/>
|
2607 |
<input type="hidden" name="task" value=""/>
|
2608 |
</form>
|
2615 |
|
2616 |
?>
|
2617 |
<script>
|
2618 |
+
jQuery(function() {
|
2619 |
+
jQuery( "#tabs" ).tabs();
|
2620 |
});
|
2621 |
</script>
|
2622 |
|
2634 |
</table>
|
2635 |
</p></div>
|
2636 |
</div>
|
2637 |
+
<form action="" name="adminForm" method="post">
|
2638 |
<input type="hidden" name="option" value="<?php echo $option; ?>"/>
|
2639 |
<input type="hidden" name="task" value=""/>
|
2640 |
</form>
|
2646 |
global $_CONFIG;
|
2647 |
|
2648 |
?>
|
2649 |
+
<form action="" method="post" name="adminForm">
|
2650 |
<table border="0" align="center" cellspacing="0" cellpadding="2" width="100%" class="adminform">
|
2651 |
<tr><th colspan='2'>
|
2652 |
<?php echo LM_RENAME_TOP?>
|
2666 |
|
2667 |
?>
|
2668 |
</table>
|
2669 |
+
<form action="" name="adminForm" method="post">
|
2670 |
<input type="hidden" name="option" value="<?php echo $option; ?>"/>
|
2671 |
<input type="hidden" name="task" value="rename_save"/>
|
2672 |
</form>
|
admin.cloner.php
CHANGED
@@ -21,82 +21,63 @@
|
|
21 |
*/
|
22 |
|
23 |
|
24 |
-
|
25 |
-
@set_time_limit("3600");
|
26 |
-
@error_reporting(E_ALL ^ E_NOTICE);
|
27 |
|
28 |
-
|
|
|
29 |
|
30 |
-
|
31 |
-
|
32 |
-
require_once($config_file);
|
33 |
-
require_once("restore/TAR.php");
|
34 |
-
require_once("cloner.functions.php");
|
35 |
-
require_once("admin.cloner.html.php");
|
36 |
-
require_once("common.php");
|
37 |
|
38 |
-
|
39 |
|
40 |
-
|
41 |
-
|
42 |
-
|
|
|
43 |
|
44 |
-
|
45 |
|
46 |
-
|
|
|
|
|
|
|
47 |
|
48 |
-
HTML_cloner::footer();
|
49 |
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
@session_register('clone');
|
55 |
-
}
|
56 |
-
$_SESSION['clone'] = 1;
|
57 |
-
|
58 |
-
mosRedirect('index2.php?option=' . $option, "Welcome to XCloner backend");
|
59 |
-
} else {
|
60 |
-
|
61 |
-
|
62 |
-
mosRedirect('index2.php?option=' . $option, "Incorrect username and/or password");
|
63 |
-
}
|
64 |
-
}
|
65 |
-
|
66 |
-
//###########GLOBALS in effect
|
67 |
-
$GLOBALS['lang_dir'] = $lang_dir;
|
68 |
-
//###########
|
69 |
-
$lang_array = get_avalaible_langs();
|
70 |
-
|
71 |
-
|
72 |
-
// retrieve row selection from forms
|
73 |
-
$cid = $_REQUEST['cid'];
|
74 |
-
if (!is_array($cid)) {
|
75 |
$cid = array(0);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
}
|
|
|
77 |
|
78 |
-
|
79 |
-
if (($task != 'download') and (($_REQUEST['task']!="refresh") or (!$_CONFIG['refresh_mode'])))
|
80 |
-
HTML_cloner::header();
|
81 |
-
|
82 |
-
//########## SETTING THE GLOBALS VARIABLES #########################
|
83 |
|
84 |
-
|
85 |
|
86 |
-
|
87 |
|
88 |
-
|
89 |
|
90 |
-
|
91 |
|
92 |
-
|
93 |
|
94 |
-
|
95 |
|
96 |
-
|
97 |
|
98 |
-
|
99 |
-
|
100 |
case 'rename_save':
|
101 |
case 'rename':
|
102 |
clone_rename($option);
|
@@ -104,10 +85,10 @@
|
|
104 |
case 'action':
|
105 |
action($option);
|
106 |
break;
|
107 |
-
|
108 |
-
|
109 |
case 'cancel_lang':
|
110 |
-
mosRedirect('
|
111 |
break;
|
112 |
case 'add_lang':
|
113 |
case 'add_lang_new':
|
@@ -118,32 +99,32 @@
|
|
118 |
case 'edit_lang':
|
119 |
translator_edit($option, $task);
|
120 |
break;
|
121 |
-
|
122 |
-
|
123 |
case 'del_lang':
|
124 |
case 'lang':
|
125 |
translator($option);
|
126 |
break;
|
127 |
-
|
128 |
case 'recurse_database';
|
129 |
goRecurseDatabases();
|
130 |
break;
|
131 |
-
|
132 |
case 'recurse_files':
|
133 |
goRecurseFiles();
|
134 |
break;
|
135 |
-
|
136 |
case 'cleanup':
|
137 |
include_once("classes/main.class.php");
|
138 |
$main = new Main();
|
139 |
$main->init($_CONFIG);
|
140 |
$main->cleanUp();
|
141 |
break;
|
142 |
-
|
143 |
case 'refresh':
|
144 |
generateBackuprefresh($cid, $option, $_REQUEST['backup'], $_CONFIG['refresh_mode']);
|
145 |
break;
|
146 |
-
|
147 |
case 'generate':
|
148 |
if($_CONFIG['refresh_mode']){
|
149 |
$_REQUEST['mode'] = "start";
|
@@ -154,7 +135,7 @@
|
|
154 |
}
|
155 |
generateBackup($cid, $option);
|
156 |
break;
|
157 |
-
|
158 |
case 'confirm':
|
159 |
deleteXLog();
|
160 |
confirmBackup($option);
|
@@ -163,25 +144,26 @@
|
|
163 |
downloadBackup($_REQUEST[file]);
|
164 |
break;
|
165 |
case 'cron':
|
166 |
-
|
167 |
break;
|
168 |
case 'about':
|
169 |
case 'credits':
|
170 |
showHelp($option);
|
171 |
break;
|
172 |
case 'restore':
|
173 |
-
|
174 |
break;
|
175 |
-
|
176 |
case 'cron_delete':
|
177 |
if (unlink($_CONFIG['multiple_config_dir'] . "/" . $_REQUEST['fconfig']))
|
178 |
$msg = " was deleted";
|
179 |
else
|
180 |
$msg = " was not deleted, please delete it manually!";
|
181 |
-
|
182 |
-
mosRedirect('
|
183 |
break;
|
184 |
-
|
|
|
185 |
case 'remove':
|
186 |
deleteBackups($cid, $option);
|
187 |
break;
|
@@ -190,15 +172,15 @@
|
|
190 |
case 'clone':
|
191 |
moveBackup($option);
|
192 |
break;
|
193 |
-
|
194 |
case 'cancel':
|
195 |
-
mosRedirect('
|
196 |
break;
|
197 |
case 'config':
|
198 |
config($option);
|
199 |
break;
|
200 |
case 'rename_cancel':
|
201 |
-
mosRedirect('
|
202 |
break;
|
203 |
case 'show':
|
204 |
case 'view':
|
@@ -210,11 +192,13 @@
|
|
210 |
default:
|
211 |
fdefault();
|
212 |
break;
|
213 |
-
|
|
|
|
|
214 |
|
215 |
-
|
216 |
-
|
217 |
-
|
|
|
218 |
|
219 |
-
@mysql_close($link);
|
220 |
?>
|
21 |
*/
|
22 |
|
23 |
|
24 |
+
defined( '_VALID_MOS' ) or die( 'Restricted access' );
|
|
|
|
|
25 |
|
26 |
+
@set_time_limit("3600");
|
27 |
+
@error_reporting(E_ALL ^ E_NOTICE);
|
28 |
|
29 |
+
//load configuration
|
30 |
+
$config_file = __XCLONERDIR__."/cloner.config.php";
|
|
|
|
|
|
|
|
|
|
|
31 |
|
32 |
+
require_once($config_file);
|
33 |
|
34 |
+
require_once("restore/TAR.php");
|
35 |
+
require_once("cloner.functions.php");
|
36 |
+
require_once("admin.cloner.html.php");
|
37 |
+
require_once("common.php");
|
38 |
|
39 |
+
$option = "xcloner";
|
40 |
|
41 |
+
//###########GLOBALS in effect
|
42 |
+
$GLOBALS['lang_dir'] = $lang_dir;
|
43 |
+
//###########
|
44 |
+
$lang_array = get_avalaible_langs();
|
45 |
|
|
|
46 |
|
47 |
+
// retrieve row selection from forms
|
48 |
+
$cid = $_REQUEST['cid'];
|
49 |
+
if (!is_array($cid))
|
50 |
+
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
$cid = array(0);
|
52 |
+
}
|
53 |
+
|
54 |
+
if(!$_REQUEST['nohtml'])
|
55 |
+
{
|
56 |
+
if (($task != 'download') and (($_REQUEST['task']!="refresh") or (!$_CONFIG['refresh_mode']))){
|
57 |
+
//HTML_cloner::header();
|
58 |
+
$html = new HTML_cloner();
|
59 |
+
$html->header();
|
60 |
}
|
61 |
+
}
|
62 |
|
63 |
+
//########## SETTING THE GLOBALS VARIABLES #########################
|
|
|
|
|
|
|
|
|
64 |
|
65 |
+
$GLOBALS['joomla_compatible'] = $joomla_compatible;
|
66 |
|
67 |
+
$GLOBALS['_CONFIG'] = $_CONFIG;
|
68 |
|
69 |
+
$GLOBALS['clonerPath'] = $clonerPath;
|
70 |
|
71 |
+
$GLOBALS['baDownloadPath'] = $baDownloadPath;
|
72 |
|
73 |
+
$GLOBALS['config_file'] = $config_file;
|
74 |
|
75 |
+
$GLOBALS['lang_array'] = $lang_array;
|
76 |
|
77 |
+
openXLog();
|
78 |
|
79 |
+
// process the workflow selection
|
80 |
+
switch ($task) {
|
81 |
case 'rename_save':
|
82 |
case 'rename':
|
83 |
clone_rename($option);
|
85 |
case 'action':
|
86 |
action($option);
|
87 |
break;
|
88 |
+
|
89 |
+
|
90 |
case 'cancel_lang':
|
91 |
+
mosRedirect('plugins.php?page=xcloner_show&option=' . $option . "&task=lang");
|
92 |
break;
|
93 |
case 'add_lang':
|
94 |
case 'add_lang_new':
|
99 |
case 'edit_lang':
|
100 |
translator_edit($option, $task);
|
101 |
break;
|
102 |
+
|
103 |
+
|
104 |
case 'del_lang':
|
105 |
case 'lang':
|
106 |
translator($option);
|
107 |
break;
|
108 |
+
|
109 |
case 'recurse_database';
|
110 |
goRecurseDatabases();
|
111 |
break;
|
112 |
+
|
113 |
case 'recurse_files':
|
114 |
goRecurseFiles();
|
115 |
break;
|
116 |
+
|
117 |
case 'cleanup':
|
118 |
include_once("classes/main.class.php");
|
119 |
$main = new Main();
|
120 |
$main->init($_CONFIG);
|
121 |
$main->cleanUp();
|
122 |
break;
|
123 |
+
|
124 |
case 'refresh':
|
125 |
generateBackuprefresh($cid, $option, $_REQUEST['backup'], $_CONFIG['refresh_mode']);
|
126 |
break;
|
127 |
+
|
128 |
case 'generate':
|
129 |
if($_CONFIG['refresh_mode']){
|
130 |
$_REQUEST['mode'] = "start";
|
135 |
}
|
136 |
generateBackup($cid, $option);
|
137 |
break;
|
138 |
+
|
139 |
case 'confirm':
|
140 |
deleteXLog();
|
141 |
confirmBackup($option);
|
144 |
downloadBackup($_REQUEST[file]);
|
145 |
break;
|
146 |
case 'cron':
|
147 |
+
$html->Cron();
|
148 |
break;
|
149 |
case 'about':
|
150 |
case 'credits':
|
151 |
showHelp($option);
|
152 |
break;
|
153 |
case 'restore':
|
154 |
+
$html->Restore($option);
|
155 |
break;
|
156 |
+
|
157 |
case 'cron_delete':
|
158 |
if (unlink($_CONFIG['multiple_config_dir'] . "/" . $_REQUEST['fconfig']))
|
159 |
$msg = " was deleted";
|
160 |
else
|
161 |
$msg = " was not deleted, please delete it manually!";
|
162 |
+
|
163 |
+
mosRedirect('plugins.php?page=xcloner_show&option=' . $option . "&task=config", $_REQUEST['fconfig'] . $msg);
|
164 |
break;
|
165 |
+
|
166 |
+
case 'delete':
|
167 |
case 'remove':
|
168 |
deleteBackups($cid, $option);
|
169 |
break;
|
172 |
case 'clone':
|
173 |
moveBackup($option);
|
174 |
break;
|
175 |
+
|
176 |
case 'cancel':
|
177 |
+
mosRedirect('plugins.php?page=xcloner_show&option=' . $option);
|
178 |
break;
|
179 |
case 'config':
|
180 |
config($option);
|
181 |
break;
|
182 |
case 'rename_cancel':
|
183 |
+
mosRedirect('plugins.php?page=xcloner_show&option=' . $option . "&task=view");
|
184 |
break;
|
185 |
case 'show':
|
186 |
case 'view':
|
192 |
default:
|
193 |
fdefault();
|
194 |
break;
|
195 |
+
}
|
196 |
+
|
197 |
+
closeXLog();
|
198 |
|
199 |
+
if(!$_REQUEST['nohtml'])
|
200 |
+
{
|
201 |
+
$html->footer();
|
202 |
+
}
|
203 |
|
|
|
204 |
?>
|
admin.xcloner-backupandrestore.php
DELETED
@@ -1,5 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
print "<iframe src='components/com_xcloner-backupandrestore/index.php' width='100%' height='900' frameborder=0 marginWidth=0 frameSpacing=0 marginHeight=110 ></iframe>";
|
4 |
-
|
5 |
-
?>
|
|
|
|
|
|
|
|
|
|
admin.xcloner.php
DELETED
@@ -1,10 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
// no direct access
|
4 |
-
if(!defined( '_VALID_MOS' ) && !defined('_JEXEC'))
|
5 |
-
|
6 |
-
die( 'Restricted access' );
|
7 |
-
|
8 |
-
print "<iframe src='components/com_xcloner/index.php' width='100%' height='900' frameborder=0 marginWidth=0 frameSpacing=0 marginHeight=110 ></iframe>";
|
9 |
-
|
10 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
administrator/.htaccess
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
order deny,allow
|
2 |
+
deny from all
|
administrator/backups/.htaccess
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
order deny,allow
|
2 |
+
deny from all
|
browser/files_inpage.php
CHANGED
@@ -1,7 +1,5 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
4 |
-
define("_VALID_MOS", 1);
|
5 |
|
6 |
$thisApp=$_SERVER['PHP_SELF'] . "?browse=true";
|
7 |
|
1 |
<?php
|
2 |
+
defined( '_VALID_MOS' ) or die( 'Restricted access' );
|
|
|
|
|
3 |
|
4 |
$thisApp=$_SERVER['PHP_SELF'] . "?browse=true";
|
5 |
|
browser/files_xml.php
CHANGED
@@ -10,38 +10,25 @@
|
|
10 |
* Date: November 2010
|
11 |
**/
|
12 |
|
13 |
-
|
14 |
-
|
15 |
-
session_start();
|
16 |
-
if(!isset($_SESSION['clone'])){
|
17 |
-
echo "Not Authorized";
|
18 |
-
exit;
|
19 |
-
}
|
20 |
|
21 |
header("Cache-Control: no-cache");
|
22 |
header("Pragma: nocache");
|
23 |
-
header("Content-Type: text/xml");
|
24 |
|
25 |
error_reporting(2);
|
26 |
|
27 |
-
|
28 |
-
|
29 |
-
echo "Access denied to this location!";
|
30 |
-
exit;
|
31 |
-
}
|
32 |
-
|
33 |
-
|
34 |
-
include("../cloner.config.php");
|
35 |
-
include("../common.php");
|
36 |
-
|
37 |
|
38 |
if((strlen($_REQUEST['dir']) < strlen($_CONFIG['backup_path']))&&($_REQUEST[dir] != ''))
|
39 |
-
|
40 |
$dir = $_CONFIG['backup_path'];
|
41 |
-
|
42 |
else
|
43 |
-
|
44 |
$dir = ($_REQUEST['dir'] != '') ? $_REQUEST['dir'] : $_CONFIG['backup_path'];
|
|
|
45 |
|
46 |
$fulldir = $dir;
|
47 |
$f_arr = array();
|
10 |
* Date: November 2010
|
11 |
**/
|
12 |
|
13 |
+
defined( '_VALID_MOS' ) or die( 'Restricted access' );
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
|
15 |
header("Cache-Control: no-cache");
|
16 |
header("Pragma: nocache");
|
17 |
+
header("Content-Type: text/xml; charset=utf-8");
|
18 |
|
19 |
error_reporting(2);
|
20 |
|
21 |
+
include(realpath(dirname(__FILE__))."/../cloner.config.php");
|
22 |
+
include(realpath(dirname(__FILE__)) ."/../common.php");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
if((strlen($_REQUEST['dir']) < strlen($_CONFIG['backup_path']))&&($_REQUEST[dir] != ''))
|
25 |
+
{
|
26 |
$dir = $_CONFIG['backup_path'];
|
27 |
+
}
|
28 |
else
|
29 |
+
{
|
30 |
$dir = ($_REQUEST['dir'] != '') ? $_REQUEST['dir'] : $_CONFIG['backup_path'];
|
31 |
+
}
|
32 |
|
33 |
$fulldir = $dir;
|
34 |
$f_arr = array();
|
browser/xmlhttp.js
CHANGED
@@ -36,7 +36,7 @@ function processXMLRequest() {
|
|
36 |
function do_browser(){
|
37 |
targetDiv=document.getElementById("browser");
|
38 |
|
39 |
-
if(loadXMLDoc("
|
40 |
targetDiv.className="searching";
|
41 |
targetDiv.innerHTML="";
|
42 |
}
|
@@ -110,24 +110,24 @@ function useXML(xmlInfo){
|
|
110 |
else
|
111 |
loc1 = loc;
|
112 |
|
113 |
-
var newloc1="
|
114 |
|
115 |
var stringHTML="<p><b>" + loc1 +"</b> <br /><br /></p>";
|
116 |
|
117 |
if(loc.indexOf("/")!=-1){
|
118 |
-
var newfile="
|
119 |
stringHTML=stringHTML+"<p><a href=\"#\" onclick=\"loadXMLDoc('" + newfile +"')\">[Up a level]</a> <a href='#' onclick=\"loadXMLDoc('" + newloc1 +"&act=checkall')\" >[check all]</a> <a href='#' onclick=\"loadXMLDoc('" + newloc1 +"&act=uncheckall')\" >[uncheck all]</a></p><br />"
|
120 |
}
|
121 |
if(infoTags[0].hasChildNodes){
|
122 |
stringHTML=stringHTML+"<ul>";
|
123 |
for(node=infoTags[0].firstChild; node!=null; node=node.nextSibling){
|
124 |
|
125 |
-
var newloc="
|
126 |
path = loc+"/"+node.firstChild.nodeValue;
|
127 |
|
128 |
if(node.nodeName=="file"){
|
129 |
|
130 |
-
stringHTML=stringHTML+"<li class=\"file\"><img src='browser/file.gif' border='0'><input type=checkbox "+node.getAttribute('check')+" onclick=\"loadXMLDoc('" + newloc +"&path="+path+"')\" name=cid[] value='"+path+"'><a href=\"" +node.getAttribute('link')+ "\">"+node.firstChild.nodeValue+"</a></li>";
|
131 |
|
132 |
}
|
133 |
if(node.nodeName=="message"){
|
@@ -139,8 +139,8 @@ function useXML(xmlInfo){
|
|
139 |
if(node.nodeName=="folder"){
|
140 |
|
141 |
|
142 |
-
var newfile="
|
143 |
-
stringHTML=stringHTML+"<li class=\"folder\"><img src='browser/folder.gif' border='0'><input type=checkbox "+node.getAttribute('check')+" onclick=\"loadXMLDoc('" + newloc +"&path="+path+"')\" name=cid[] value='"+path+"'><a href='#' class=\"folder\" onclick=\"loadXMLDoc('" + newfile+"')\">"+node.firstChild.nodeValue+"</a></li>";
|
144 |
}
|
145 |
}
|
146 |
stringHTML=stringHTML+"</ul>";
|
36 |
function do_browser(){
|
37 |
targetDiv=document.getElementById("browser");
|
38 |
|
39 |
+
if(loadXMLDoc("admin-ajax.php?action=files_xml")){
|
40 |
targetDiv.className="searching";
|
41 |
targetDiv.innerHTML="";
|
42 |
}
|
110 |
else
|
111 |
loc1 = loc;
|
112 |
|
113 |
+
var newloc1="admin-ajax.php?action=files_xml&dir=" + loc ;
|
114 |
|
115 |
var stringHTML="<p><b>" + loc1 +"</b> <br /><br /></p>";
|
116 |
|
117 |
if(loc.indexOf("/")!=-1){
|
118 |
+
var newfile="admin-ajax.php?action=files_xml&dir=" + loc.slice(0, loc.lastIndexOf("/"));
|
119 |
stringHTML=stringHTML+"<p><a href=\"#\" onclick=\"loadXMLDoc('" + newfile +"')\">[Up a level]</a> <a href='#' onclick=\"loadXMLDoc('" + newloc1 +"&act=checkall')\" >[check all]</a> <a href='#' onclick=\"loadXMLDoc('" + newloc1 +"&act=uncheckall')\" >[uncheck all]</a></p><br />"
|
120 |
}
|
121 |
if(infoTags[0].hasChildNodes){
|
122 |
stringHTML=stringHTML+"<ul>";
|
123 |
for(node=infoTags[0].firstChild; node!=null; node=node.nextSibling){
|
124 |
|
125 |
+
var newloc="admin-ajax.php?action=files_xml&dir=" + loc ;
|
126 |
path = loc+"/"+node.firstChild.nodeValue;
|
127 |
|
128 |
if(node.nodeName=="file"){
|
129 |
|
130 |
+
stringHTML=stringHTML+"<li class=\"file\"><img src='../wp-content/plugins/xcloner-backup-and-restore/browser/file.gif' border='0'><input type=checkbox "+node.getAttribute('check')+" onclick=\"loadXMLDoc('" + newloc +"&path="+path+"')\" name=cid[] value='"+path+"'><a href=\"" +node.getAttribute('link')+ "\">"+node.firstChild.nodeValue+"</a></li>";
|
131 |
|
132 |
}
|
133 |
if(node.nodeName=="message"){
|
139 |
if(node.nodeName=="folder"){
|
140 |
|
141 |
|
142 |
+
var newfile="admin-ajax.php?action=files_xml&dir=" + loc + "/" + node.firstChild.nodeValue;
|
143 |
+
stringHTML=stringHTML+"<li class=\"folder\"><img src='../wp-content/plugins/xcloner-backup-and-restore/browser/folder.gif' border='0'><input type=checkbox "+node.getAttribute('check')+" onclick=\"loadXMLDoc('" + newloc +"&path="+path+"')\" name=cid[] value='"+path+"'><a href='#' class=\"folder\" onclick=\"loadXMLDoc('" + newfile+"')\">"+node.firstChild.nodeValue+"</a></li>";
|
144 |
}
|
145 |
}
|
146 |
stringHTML=stringHTML+"</ul>";
|
classes/.htaccess
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
order deny,allow
|
2 |
+
deny from all
|
classes/DropboxClient.php
ADDED
@@ -0,0 +1,659 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* DropPHP - A simple Dropbox client that works without cURL.
|
4 |
+
*
|
5 |
+
* http://fabi.me/en/php-projects/dropphp-dropbox-api-client/
|
6 |
+
*
|
7 |
+
*
|
8 |
+
* @author Fabian Schlieper <fabian@fabi.me>
|
9 |
+
* @copyright Fabian Schlieper 2012
|
10 |
+
* @version 1.6
|
11 |
+
* @license See LICENSE
|
12 |
+
*
|
13 |
+
*/
|
14 |
+
|
15 |
+
require_once(dirname(__FILE__)."/OAuthSimple.php");
|
16 |
+
|
17 |
+
class DropboxClient {
|
18 |
+
|
19 |
+
const API_URL = "https://api.dropbox.com/1/";
|
20 |
+
const API_CONTENT_URL = "https://api-content.dropbox.com/1/";
|
21 |
+
|
22 |
+
const BUFFER_SIZE = 4096;
|
23 |
+
|
24 |
+
const MAX_UPLOAD_CHUNK_SIZE = 150000000; // 150MB
|
25 |
+
|
26 |
+
const UPLOAD_CHUNK_SIZE = 4000000; // 4MB
|
27 |
+
|
28 |
+
private $appParams;
|
29 |
+
private $consumerToken;
|
30 |
+
|
31 |
+
private $requestToken;
|
32 |
+
private $accessToken;
|
33 |
+
|
34 |
+
private $locale;
|
35 |
+
private $rootPath;
|
36 |
+
|
37 |
+
private $useCurl;
|
38 |
+
|
39 |
+
function __construct ($app_params, $locale = "en"){
|
40 |
+
$this->appParams = $app_params;
|
41 |
+
if(empty($app_params['app_key']))
|
42 |
+
throw new DropboxException("App Key is empty!");
|
43 |
+
|
44 |
+
$this->consumerToken = array('t' => $this->appParams['app_key'], 's' => $this->appParams['app_secret']);
|
45 |
+
$this->locale = $locale;
|
46 |
+
$this->rootPath = empty($app_params['app_full_access']) ? "sandbox" : "dropbox";
|
47 |
+
|
48 |
+
$this->requestToken = null;
|
49 |
+
$this->accessToken = null;
|
50 |
+
|
51 |
+
$this->useCurl = function_exists('curl_init');
|
52 |
+
}
|
53 |
+
|
54 |
+
/**
|
55 |
+
* Sets whether to use cURL if its available or PHP HTTP wrappers otherwise
|
56 |
+
*
|
57 |
+
* @access public
|
58 |
+
* @return boolean Whether to actually use cURL (always false if not installed)
|
59 |
+
*/
|
60 |
+
public function SetUseCUrl($use_it)
|
61 |
+
{
|
62 |
+
return ($this->useCurl = $use_it && function_exists('curl_init'));
|
63 |
+
}
|
64 |
+
|
65 |
+
// ##################################################
|
66 |
+
// Authorization
|
67 |
+
|
68 |
+
/**
|
69 |
+
* Step 1 of authentication process. Retrieves a request token or returns a previously retrieved one.
|
70 |
+
*
|
71 |
+
* @access public
|
72 |
+
* @param boolean $get_new_token Optional (default false). Wether to retrieve a new request token.
|
73 |
+
* @return array Request Token array.
|
74 |
+
*/
|
75 |
+
public function GetRequestToken($get_new_token=false)
|
76 |
+
{
|
77 |
+
if(!empty($this->requestToken) && !$get_new_token)
|
78 |
+
return $this->requestToken;
|
79 |
+
|
80 |
+
$rt = $this->authCall("oauth/request_token");
|
81 |
+
if(empty($rt) || empty($rt['oauth_token']))
|
82 |
+
throw new DropboxException('Could not get request token!');
|
83 |
+
|
84 |
+
return ($this->requestToken = array('t'=>$rt['oauth_token'], 's'=>$rt['oauth_token_secret']));
|
85 |
+
}
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Step 2. Returns a URL the user must be redirected to in order to connect the app to their Dropbox account
|
89 |
+
*
|
90 |
+
* @access public
|
91 |
+
* @param string $return_url URL users are redirected after authorization
|
92 |
+
* @return string URL
|
93 |
+
*/
|
94 |
+
public function BuildAuthorizeUrl($return_url)
|
95 |
+
{
|
96 |
+
$rt = $this->GetRequestToken();
|
97 |
+
if(empty($rt) || empty($rt['t'])) throw new DropboxException('Request Token Invalid ('.print_r($rt,true).').');
|
98 |
+
return "https://www.dropbox.com/1/oauth/authorize?oauth_token=".$rt['t']."&oauth_callback=".urlencode($return_url);
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Step 3. Acquires an access token. This is the final step of authentication.
|
103 |
+
*
|
104 |
+
* @access public
|
105 |
+
* @param array $request_token Optional. The previously retrieved request token. This parameter can only be skipped if the DropboxClient object has been (de)serialized.
|
106 |
+
* @return array Access Token array.
|
107 |
+
*/
|
108 |
+
public function GetAccessToken($request_token = null)
|
109 |
+
{
|
110 |
+
if(!empty($this->accessToken)) return $this->accessToken;
|
111 |
+
|
112 |
+
if(empty($request_token)) $request_token = $this->requestToken;
|
113 |
+
if(empty($request_token)) throw new DropboxException('Request token required!');
|
114 |
+
|
115 |
+
$at = $this->authCall("oauth/access_token", $request_token);
|
116 |
+
if(empty($at))
|
117 |
+
throw new DropboxException(sprintf('Could not get access token! (request token: %s)', $request_token['t']));
|
118 |
+
|
119 |
+
return ($this->accessToken = array('t'=>$at['oauth_token'], 's'=>$at['oauth_token_secret']));
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Sets a previously retrieved (and stored) access token.
|
124 |
+
*
|
125 |
+
* @access public
|
126 |
+
* @param string|object $token The Access Token
|
127 |
+
* @return none
|
128 |
+
*/
|
129 |
+
public function SetAccessToken($token)
|
130 |
+
{
|
131 |
+
if(empty($token['t']) || empty($token['s'])) throw new DropboxException('Passed invalid access token.');
|
132 |
+
$this->accessToken = $token;
|
133 |
+
}
|
134 |
+
|
135 |
+
/**
|
136 |
+
* Checks if an access token has been set.
|
137 |
+
*
|
138 |
+
* @access public
|
139 |
+
* @return boolean Authorized or not
|
140 |
+
*/
|
141 |
+
public function IsAuthorized()
|
142 |
+
{
|
143 |
+
if(empty($this->accessToken)) return false;
|
144 |
+
return true;
|
145 |
+
}
|
146 |
+
|
147 |
+
|
148 |
+
// ##################################################
|
149 |
+
// API Functions
|
150 |
+
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Retrieves information about the user's account.
|
154 |
+
*
|
155 |
+
* @access public
|
156 |
+
* @return object Account info object. See https://www.dropbox.com/developers/reference/api#account-info
|
157 |
+
*/
|
158 |
+
public function GetAccountInfo()
|
159 |
+
{
|
160 |
+
return $this->apiCall("account/info", "GET");
|
161 |
+
}
|
162 |
+
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Get file list of a dropbox folder.
|
166 |
+
*
|
167 |
+
* @access public
|
168 |
+
* @param string|object $dropbox_path Dropbox path of the folder
|
169 |
+
* @return array An array with metadata of files/folders keyed by paths
|
170 |
+
*/
|
171 |
+
public function GetFiles($dropbox_path='', $recursive=false, $include_deleted=false)
|
172 |
+
{
|
173 |
+
if(is_object($dropbox_path) && !empty($dropbox_path->path)) $dropbox_path = $dropbox_path->path;
|
174 |
+
return $this->getFileTree($dropbox_path, $include_deleted, $recursive ? 1000 : 0);
|
175 |
+
}
|
176 |
+
|
177 |
+
/**
|
178 |
+
* Get file or folder metadata
|
179 |
+
*
|
180 |
+
* @access public
|
181 |
+
* @param $dropbox_path string Dropbox path of the file or folder
|
182 |
+
*/
|
183 |
+
public function GetMetadata($dropbox_path, $include_deleted=false, $rev=null)
|
184 |
+
{
|
185 |
+
if(is_object($dropbox_path) && !empty($dropbox_path->path)) $dropbox_path = $dropbox_path->path;
|
186 |
+
return $this->apiCall("metadata/$this->rootPath/$dropbox_path", "GET", compact('include_deleted','rev'));
|
187 |
+
}
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Download a file to the webserver
|
191 |
+
*
|
192 |
+
* @access public
|
193 |
+
* @param string|object $dropbox_file Dropbox path or metadata object of the file to download.
|
194 |
+
* @param string $dest_path Local path for destination
|
195 |
+
* @param string $rev Optional. The revision of the file to retrieve. This defaults to the most recent revision.
|
196 |
+
* @param callback $progress_changed_callback Optional. Callback that will be called during download with 2 args: 1. bytes loaded, 2. file size
|
197 |
+
* @return object Dropbox file metadata
|
198 |
+
*/
|
199 |
+
public function DownloadFile($dropbox_file, $dest_path='', $rev=null, $progress_changed_callback = null)
|
200 |
+
{
|
201 |
+
if(is_object($dropbox_file) && !empty($dropbox_file->path))
|
202 |
+
$dropbox_file = $dropbox_file->path;
|
203 |
+
|
204 |
+
if(empty($dest_path)) $dest_path = basename($dropbox_file);
|
205 |
+
|
206 |
+
$url = $this->cleanUrl(self::API_CONTENT_URL."/files/$this->rootPath/$dropbox_file")
|
207 |
+
. (!empty($rev) ? ('?'.http_build_query(array('rev' => $rev),'','&')) : '');
|
208 |
+
$context = $this->createRequestContext($url, "GET");
|
209 |
+
|
210 |
+
$fh = @fopen($dest_path, 'wb'); // write binary
|
211 |
+
if($fh === false) {
|
212 |
+
@fclose($rh);
|
213 |
+
throw new DropboxException("Could not create file $dest_path !");
|
214 |
+
}
|
215 |
+
|
216 |
+
if($this->useCurl) {
|
217 |
+
curl_setopt($context, CURLOPT_BINARYTRANSFER, true);
|
218 |
+
curl_setopt($context, CURLOPT_RETURNTRANSFER, true);
|
219 |
+
curl_setopt($context, CURLOPT_FILE, $fh);
|
220 |
+
$response_headers = array();
|
221 |
+
self::execCurlAndClose($context, $response_headers);
|
222 |
+
fclose($fh);
|
223 |
+
$meta = self::getMetaFromHeaders($response_headers);
|
224 |
+
$bytes_loaded = filesize($dest_path);
|
225 |
+
} else {
|
226 |
+
$rh = @fopen($url, 'rb', false, $context); // read binary
|
227 |
+
if($rh === false)
|
228 |
+
throw new DropboxException("HTTP request to $url failed!");
|
229 |
+
|
230 |
+
|
231 |
+
// get file meta from HTTP header
|
232 |
+
$s_meta = stream_get_meta_data($rh);
|
233 |
+
$meta = self::getMetaFromHeaders($s_meta['wrapper_data']);
|
234 |
+
$bytes_loaded = 0;
|
235 |
+
while (!feof($rh)) {
|
236 |
+
if(($s=fwrite($fh, fread($rh, self::BUFFER_SIZE))) === false) {
|
237 |
+
@fclose($rh);
|
238 |
+
@fclose($fh);
|
239 |
+
throw new DropboxException("Writing to file $dest_path failed!'");
|
240 |
+
}
|
241 |
+
$bytes_loaded += $s;
|
242 |
+
if(!empty($progress_changed_callback)) {
|
243 |
+
call_user_func($progress_changed_callback, $bytes_loaded, $meta->bytes);
|
244 |
+
}
|
245 |
+
}
|
246 |
+
|
247 |
+
fclose($rh);
|
248 |
+
fclose($fh);
|
249 |
+
}
|
250 |
+
|
251 |
+
if($meta->bytes != $bytes_loaded)
|
252 |
+
throw new DropboxException("Download size mismatch! (header:{$meta->bytes} vs actual:{$bytes_loaded}");
|
253 |
+
|
254 |
+
return $meta;
|
255 |
+
}
|
256 |
+
|
257 |
+
/**
|
258 |
+
* Upload a file to dropbox
|
259 |
+
*
|
260 |
+
* @access public
|
261 |
+
* @param $src_file string Local file to upload
|
262 |
+
* @param $dropbox_path string Dropbox path for destination
|
263 |
+
* @return object Dropbox file metadata
|
264 |
+
*/
|
265 |
+
public function UploadFile($src_file, $dropbox_path='', $overwrite=true, $parent_rev=null)
|
266 |
+
{
|
267 |
+
if(empty($dropbox_path)) $dropbox_path = basename($src_file);
|
268 |
+
elseif(is_object($dropbox_path) && !empty($dropbox_path->path)) $dropbox_path = $dropbox_path->path;
|
269 |
+
|
270 |
+
$file_size = filesize($src_file);
|
271 |
+
|
272 |
+
if($file_size > self::MAX_UPLOAD_CHUNK_SIZE)
|
273 |
+
{
|
274 |
+
$fh = fopen($src_file,'rb');
|
275 |
+
if($fh === false)
|
276 |
+
throw new DropboxException();
|
277 |
+
|
278 |
+
$upload_id = null;
|
279 |
+
$offset = 0;
|
280 |
+
|
281 |
+
|
282 |
+
while(!feof($fh)) {
|
283 |
+
$url = $this->cleanUrl(self::API_CONTENT_URL."/chunked_upload").'?'.http_build_query(compact('upload_id', 'offset'),'','&');
|
284 |
+
|
285 |
+
if($this->useCurl) {
|
286 |
+
$context = $this->createRequestContext($url, "PUT");
|
287 |
+
curl_setopt($context, CURLOPT_BINARYTRANSFER, true);
|
288 |
+
curl_setopt($context, CURLOPT_PUT, 1);
|
289 |
+
curl_setopt($context, CURLOPT_INFILE, $fh);
|
290 |
+
$chunk_size = min(self::UPLOAD_CHUNK_SIZE, $file_size - $offset);
|
291 |
+
$offset += $chunk_size;
|
292 |
+
curl_setopt($context, CURLOPT_INFILESIZE, $chunk_size);
|
293 |
+
$response = json_decode(self::execCurlAndClose($context));
|
294 |
+
|
295 |
+
fseek($fh,$offset);
|
296 |
+
if($offset >= $file_size)
|
297 |
+
break;
|
298 |
+
} else {
|
299 |
+
$content = fread($fh, self::UPLOAD_CHUNK_SIZE);
|
300 |
+
|
301 |
+
$context = $this->createRequestContext($url, "PUT", $content);
|
302 |
+
$offset += strlen($content);
|
303 |
+
unset($content);
|
304 |
+
|
305 |
+
$response = json_decode(file_get_contents($url, false, $context));
|
306 |
+
}
|
307 |
+
unset($context);
|
308 |
+
|
309 |
+
if(empty($upload_id)) {
|
310 |
+
$upload_id = $response->upload_id;
|
311 |
+
if(empty($upload_id)) throw new DropboxException("Upload ID empty!");
|
312 |
+
}
|
313 |
+
}
|
314 |
+
|
315 |
+
@fclose($fh);
|
316 |
+
|
317 |
+
$this->useCurl = $prev_useCurl;
|
318 |
+
|
319 |
+
return $this->apiCall("commit_chunked_upload/$this->rootPath/$dropbox_path", "POST", compact('overwrite','parent_rev','upload_id'), true);
|
320 |
+
}
|
321 |
+
|
322 |
+
$query = http_build_query(array_merge(compact('overwrite', 'parent_rev'), array('locale' => $this->locale)),'','&');
|
323 |
+
$url = $this->cleanUrl(self::API_CONTENT_URL."/files_put/$this->rootPath/$dropbox_path")."?$query";
|
324 |
+
|
325 |
+
if($this->useCurl) {
|
326 |
+
$context = $this->createRequestContext($url, "PUT");
|
327 |
+
curl_setopt($context, CURLOPT_BINARYTRANSFER, true);
|
328 |
+
$fh = fopen($src_file, 'rb');
|
329 |
+
curl_setopt($context, CURLOPT_PUT, 1);
|
330 |
+
curl_setopt($context, CURLOPT_INFILE, $fh); // file pointer
|
331 |
+
curl_setopt($context, CURLOPT_INFILESIZE, filesize($src_file));
|
332 |
+
$meta = json_decode(self::execCurlAndClose($context));
|
333 |
+
fclose($fh);
|
334 |
+
return $meta;
|
335 |
+
} else {
|
336 |
+
$content = file_get_contents($src_file);
|
337 |
+
if(strlen($content) == 0)
|
338 |
+
throw new DropboxException("Could not read file $src_file or file is empty!");
|
339 |
+
|
340 |
+
$context = $this->createRequestContext($url, "PUT", $content);
|
341 |
+
|
342 |
+
return json_decode(file_get_contents($url, false, $context));
|
343 |
+
}
|
344 |
+
}
|
345 |
+
|
346 |
+
/**
|
347 |
+
* Get thumbnail for a specified image
|
348 |
+
*
|
349 |
+
* @access public
|
350 |
+
* @param $dropbox_file string Path to the image
|
351 |
+
* @param $format string Image format of the thumbnail (jpeg or png)
|
352 |
+
* @param $size string Thumbnail size (xs, s, m, l, xl)
|
353 |
+
* @return mime/* Returns the thumbnail as binary image data
|
354 |
+
*/
|
355 |
+
public function GetThumbnail($dropbox_file, $size = 's', $format = 'jpeg', $echo = false)
|
356 |
+
{
|
357 |
+
if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
|
358 |
+
$url = $this->cleanUrl(self::API_CONTENT_URL."thumbnails/$this->rootPath/$dropbox_file")
|
359 |
+
. '?' . http_build_query(array('format' => $format, 'size' => $size),'','&');
|
360 |
+
$context = $this->createRequestContext($url, "GET");
|
361 |
+
|
362 |
+
if($this->useCurl) {
|
363 |
+
curl_setopt($context, CURLOPT_BINARYTRANSFER, true);
|
364 |
+
curl_setopt($context, CURLOPT_RETURNTRANSFER, true);
|
365 |
+
}
|
366 |
+
|
367 |
+
$thumb = $this->useCurl ? self::execCurlAndClose($context) : file_get_contents($url, NULL, $context);
|
368 |
+
|
369 |
+
if($echo) {
|
370 |
+
header('Content-type: image/'.$format);
|
371 |
+
echo $thumb;
|
372 |
+
unset($thumb);
|
373 |
+
return;
|
374 |
+
}
|
375 |
+
|
376 |
+
return $thumb;
|
377 |
+
}
|
378 |
+
|
379 |
+
|
380 |
+
function GetLink($dropbox_file, $preview=true, $short=true, &$expires=null)
|
381 |
+
{
|
382 |
+
if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
|
383 |
+
$url = $this->apiCall(($preview?"shares":"media")."/$this->rootPath/$dropbox_file", "POST", array('locale' => null, 'short_url'=> $preview ? $short : null));
|
384 |
+
$expires = strtotime($url->expires);
|
385 |
+
return $url->url;
|
386 |
+
}
|
387 |
+
|
388 |
+
function Delta($cursor)
|
389 |
+
{
|
390 |
+
return $this->apiCall("delta", "POST", compact('cursor'));
|
391 |
+
}
|
392 |
+
|
393 |
+
function GetRevisions($dropbox_file, $rev_limit=10)
|
394 |
+
{
|
395 |
+
if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
|
396 |
+
return $this->apiCall("revisions/$this->rootPath/$dropbox_file", "GET", compact('rev_limit'));
|
397 |
+
}
|
398 |
+
|
399 |
+
function Restore($dropbox_file, $rev)
|
400 |
+
{
|
401 |
+
if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
|
402 |
+
return $this->apiCall("restore/$this->rootPath/$dropbox_file", "POST", compact('rev'));
|
403 |
+
}
|
404 |
+
|
405 |
+
function Search($path, $query, $file_limit=1000, $include_deleted=false)
|
406 |
+
{
|
407 |
+
return $this->apiCall("search/$this->rootPath/$path", "POST", compact('query','file_limit','include_deleted'));
|
408 |
+
}
|
409 |
+
|
410 |
+
function GetCopyRef($dropbox_file, &$expires=null)
|
411 |
+
{
|
412 |
+
if(is_object($dropbox_file) && !empty($dropbox_file->path)) $dropbox_file = $dropbox_file->path;
|
413 |
+
$ref = $this->apiCall("copy_ref/$this->rootPath/$dropbox_file", "GET", array('locale' => null));
|
414 |
+
$expires = strtotime($ref->expires);
|
415 |
+
return $ref->copy_ref;
|
416 |
+
}
|
417 |
+
|
418 |
+
|
419 |
+
function Copy($from_path, $to_path, $copy_ref=false)
|
420 |
+
{
|
421 |
+
if(is_object($from_path) && !empty($from_path->path)) $from_path = $from_path->path;
|
422 |
+
return $this->apiCall("fileops/copy", "POST", array('root'=> $this->rootPath, ($copy_ref ? 'from_copy_ref' : 'from_path') => $from_path, 'to_path' => $to_path));
|
423 |
+
}
|
424 |
+
|
425 |
+
/**
|
426 |
+
* Creates a new folder in the DropBox
|
427 |
+
*
|
428 |
+
* @access public
|
429 |
+
* @param $path string The path to the new folder to create
|
430 |
+
* @return object Dropbox folder metadata
|
431 |
+
*/
|
432 |
+
function CreateFolder($path)
|
433 |
+
{
|
434 |
+
return $this->apiCall("fileops/create_folder", "POST", array('root'=> $this->rootPath, 'path' => $path));
|
435 |
+
}
|
436 |
+
|
437 |
+
/**
|
438 |
+
* Delete file or folder
|
439 |
+
*
|
440 |
+
* @access public
|
441 |
+
* @param $path mixed The path or metadata of the file/folder to be deleted.
|
442 |
+
* @return object Dropbox metadata of deleted file or folder
|
443 |
+
*/
|
444 |
+
function Delete($path)
|
445 |
+
{
|
446 |
+
if(is_object($path) && !empty($path->path)) $path = $path->path;
|
447 |
+
return $this->apiCall("fileops/delete", "POST", array('locale' =>null, 'root'=> $this->rootPath, 'path' => $path));
|
448 |
+
}
|
449 |
+
|
450 |
+
function Move($from_path, $to_path)
|
451 |
+
{
|
452 |
+
if(is_object($from_path) && !empty($from_path->path)) $from_path = $from_path->path;
|
453 |
+
return $this->apiCall("fileops/move", "POST", array('root'=> $this->rootPath, 'from_path' => $from_path, 'to_path' => $to_path));
|
454 |
+
}
|
455 |
+
|
456 |
+
function getFileTree($path="", $include_deleted = false, $max_depth = 0, $depth=0)
|
457 |
+
{
|
458 |
+
static $files;
|
459 |
+
if($depth == 0) $files = array();
|
460 |
+
|
461 |
+
$dir = $this->apiCall("metadata/$this->rootPath/$path", "GET", compact('include_deleted'));
|
462 |
+
|
463 |
+
if(empty($dir) || !is_object($dir)) return false;
|
464 |
+
|
465 |
+
if(!empty($dir->error)) throw new DropboxException($dir->error);
|
466 |
+
|
467 |
+
foreach($dir->contents as $item)
|
468 |
+
{
|
469 |
+
$files[trim($item->path,'/')] = $item;
|
470 |
+
if($item->is_dir && $depth < $max_depth)
|
471 |
+
{
|
472 |
+
$this->getFileTree($item->path, $include_deleted, $max_depth, $depth+1);
|
473 |
+
}
|
474 |
+
}
|
475 |
+
|
476 |
+
return $files;
|
477 |
+
}
|
478 |
+
|
479 |
+
function createCurl($url, $http_context)
|
480 |
+
{
|
481 |
+
$ch = curl_init($url);
|
482 |
+
|
483 |
+
$curl_opts = array(
|
484 |
+
CURLOPT_HEADER => false, // exclude header from output
|
485 |
+
//CURLOPT_MUTE => true, // no output!
|
486 |
+
CURLOPT_RETURNTRANSFER => true, // but return!
|
487 |
+
CURLOPT_SSL_VERIFYPEER => false,
|
488 |
+
);
|
489 |
+
|
490 |
+
$curl_opts[CURLOPT_CUSTOMREQUEST] = $http_context['method'];
|
491 |
+
|
492 |
+
if(!empty($http_context['content'])) {
|
493 |
+
$curl_opts[CURLOPT_POSTFIELDS] =& $http_context['content'];
|
494 |
+
if(defined("CURLOPT_POSTFIELDSIZE"))
|
495 |
+
$curl_opts[CURLOPT_POSTFIELDSIZE] = strlen($http_context['content']);
|
496 |
+
}
|
497 |
+
|
498 |
+
$curl_opts[CURLOPT_HTTPHEADER] = array_map('trim',explode("\n",$http_context['header']));
|
499 |
+
|
500 |
+
curl_setopt_array($ch, $curl_opts);
|
501 |
+
return $ch;
|
502 |
+
}
|
503 |
+
|
504 |
+
static private $_curlHeadersRef;
|
505 |
+
static function _curlHeaderCallback($ch, $header)
|
506 |
+
{
|
507 |
+
self::$_curlHeadersRef[] = trim($header);
|
508 |
+
return strlen($header);
|
509 |
+
}
|
510 |
+
|
511 |
+
static function &execCurlAndClose($ch, &$out_response_headers = null)
|
512 |
+
{
|
513 |
+
if(is_array($out_response_headers)) {
|
514 |
+
self::$_curlHeadersRef =& $out_response_headers;
|
515 |
+
curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(__CLASS__, '_curlHeaderCallback'));
|
516 |
+
}
|
517 |
+
$res = curl_exec($ch);
|
518 |
+
$err_no = curl_errno($ch);
|
519 |
+
$err_str = curl_error($ch);
|
520 |
+
curl_close($ch);
|
521 |
+
if($err_no || $res === false) {
|
522 |
+
throw new DropboxException("cURL-Error ($err_no): $err_str");
|
523 |
+
}
|
524 |
+
|
525 |
+
return $res;
|
526 |
+
}
|
527 |
+
|
528 |
+
private function createRequestContext($url, $method, &$content=null, $oauth_token=-1)
|
529 |
+
{
|
530 |
+
if($oauth_token === -1)
|
531 |
+
$oauth_token = $this->accessToken;
|
532 |
+
|
533 |
+
$method = strtoupper($method);
|
534 |
+
$http_context = array('method'=>$method, 'header'=> '');
|
535 |
+
|
536 |
+
$oauth = new OAuthSimple($this->consumerToken['t'],$this->consumerToken['s']);
|
537 |
+
|
538 |
+
if(empty($oauth_token) && !empty($this->accessToken))
|
539 |
+
$oauth_token = $this->accessToken;
|
540 |
+
|
541 |
+
if(!empty($oauth_token)) {
|
542 |
+
$oauth->setParameters(array('oauth_token' => $oauth_token['t']));
|
543 |
+
$oauth->signatures(array('oauth_secret'=>$oauth_token['s']));
|
544 |
+
}
|
545 |
+
|
546 |
+
if(!empty($content)) {
|
547 |
+
$post_vars = ($method != "PUT" && preg_match("/^[a-z][a-z0-9_]*=/i", substr($content, 0, 32)));
|
548 |
+
$http_context['header'] .= "Content-Length: ".strlen($content)."\r\n";
|
549 |
+
$http_context['header'] .= "Content-Type: application/".($post_vars?"x-www-form-urlencoded":"octet-stream")."\r\n";
|
550 |
+
$http_context['content'] =& $content;
|
551 |
+
if($method == "POST" && $post_vars)
|
552 |
+
$oauth->setParameters($content);
|
553 |
+
} elseif($method == "POST") {
|
554 |
+
// make sure that content-length is always set when post request (otherwise some wrappers fail!)
|
555 |
+
$http_context['content'] = "";
|
556 |
+
$http_context['header'] .= "Content-Length: 0\r\n";
|
557 |
+
}
|
558 |
+
|
559 |
+
|
560 |
+
// check for query vars in url and add them to oauth parameters (and remove from path)
|
561 |
+
$path = $url;
|
562 |
+
$query = strrchr($url,'?');
|
563 |
+
if(!empty($query)) {
|
564 |
+
$oauth->setParameters(substr($query,1));
|
565 |
+
$path = substr($url, 0, -strlen($query));
|
566 |
+
}
|
567 |
+
|
568 |
+
|
569 |
+
$signed = $oauth->sign(array(
|
570 |
+
'action' => $method,
|
571 |
+
'path'=> $path));
|
572 |
+
//print_r($signed);
|
573 |
+
|
574 |
+
$http_context['header'] .= "Authorization: ".$signed['header']."\r\n";
|
575 |
+
|
576 |
+
return $this->useCurl ? $this->createCurl($url, $http_context) : stream_context_create(array('http'=>$http_context));
|
577 |
+
}
|
578 |
+
|
579 |
+
private function authCall($path, $request_token=null)
|
580 |
+
{
|
581 |
+
$url = $this->cleanUrl(self::API_URL.$path);
|
582 |
+
$dummy = null;
|
583 |
+
$context = $this->createRequestContext($url, "POST", $dummy, $request_token);
|
584 |
+
|
585 |
+
$contents = $this->useCurl ? self::execCurlAndClose($context) : file_get_contents($url, false, $context);
|
586 |
+
$data = array();
|
587 |
+
parse_str($contents, $data);
|
588 |
+
return $data;
|
589 |
+
}
|
590 |
+
|
591 |
+
|
592 |
+
private function apiCall($path, $method, $params=array(), $content_call=false)
|
593 |
+
{
|
594 |
+
$url = $this->cleanUrl(($content_call ? self::API_CONTENT_URL : self::API_URL).$path);
|
595 |
+
$content = http_build_query(array_merge(array('locale'=>$this->locale), $params),'','&');
|
596 |
+
|
597 |
+
if($method == "GET") {
|
598 |
+
$url .= "?".$content;
|
599 |
+
$content = null;
|
600 |
+
}
|
601 |
+
|
602 |
+
$context = $this->createRequestContext($url, $method, $content);
|
603 |
+
$json = $this->useCurl ? self::execCurlAndClose($context) : file_get_contents($url, false, $context);
|
604 |
+
//if($json === false)
|
605 |
+
// throw new DropboxException();
|
606 |
+
$resp = json_decode($json);
|
607 |
+
if(!empty($resp->error))
|
608 |
+
throw new DropboxException($resp->error);
|
609 |
+
return $resp;
|
610 |
+
}
|
611 |
+
|
612 |
+
|
613 |
+
private static function getMetaFromHeaders(&$header_array)
|
614 |
+
{
|
615 |
+
return json_decode(substr(@array_shift(array_filter($header_array, create_function('$s', 'return strpos($s, "x-dropbox-metadata:") === 0;'))), 20));
|
616 |
+
}
|
617 |
+
|
618 |
+
|
619 |
+
function cleanUrl($url) {
|
620 |
+
$p = substr($url,0,8);
|
621 |
+
$url = str_replace('//','/', str_replace('\\','/',substr($url,8)));
|
622 |
+
$url = rawurlencode($url);
|
623 |
+
$url = str_replace('%2F', '/', $url);
|
624 |
+
return $p.$url;
|
625 |
+
}
|
626 |
+
}
|
627 |
+
|
628 |
+
class DropboxException extends Exception {
|
629 |
+
|
630 |
+
public function __construct($err = null, $isDebug = FALSE)
|
631 |
+
{
|
632 |
+
if(is_null($err)) {
|
633 |
+
$el = error_get_last();
|
634 |
+
$this->message = $el['message'];
|
635 |
+
$this->file = $el['file'];
|
636 |
+
$this->line = $el['line'];
|
637 |
+
} else
|
638 |
+
$this->message = $err;
|
639 |
+
self::log_error($err);
|
640 |
+
if ($isDebug)
|
641 |
+
{
|
642 |
+
self::display_error($err, TRUE);
|
643 |
+
}
|
644 |
+
}
|
645 |
+
|
646 |
+
public static function log_error($err)
|
647 |
+
{
|
648 |
+
error_log($err, 0);
|
649 |
+
}
|
650 |
+
|
651 |
+
public static function display_error($err, $kill = FALSE)
|
652 |
+
{
|
653 |
+
print_r($err);
|
654 |
+
if ($kill === FALSE)
|
655 |
+
{
|
656 |
+
die();
|
657 |
+
}
|
658 |
+
}
|
659 |
+
}
|
classes/OAuthSimple.php
ADDED
@@ -0,0 +1,532 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* OAuthSimple - A simpler version of OAuth
|
4 |
+
*
|
5 |
+
* https://github.com/jrconlin/oauthsimple
|
6 |
+
*
|
7 |
+
* @author jr conlin <src@jrconlin.com>
|
8 |
+
* @copyright unitedHeroes.net 2011
|
9 |
+
* @version 1.3
|
10 |
+
* @license See OAuthSimple_license.txt
|
11 |
+
*
|
12 |
+
*/
|
13 |
+
|
14 |
+
class OAuthSimple {
|
15 |
+
private $_secrets;
|
16 |
+
private $_default_signature_method;
|
17 |
+
private $_action;
|
18 |
+
private $_nonce_chars;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* Constructor
|
22 |
+
*
|
23 |
+
* @access public
|
24 |
+
* @param api_key (String) The API Key (sometimes referred to as the consumer key) This value is usually supplied by the site you wish to use.
|
25 |
+
* @param shared_secret (String) The shared secret. This value is also usually provided by the site you wish to use.
|
26 |
+
* @return OAuthSimple (Object)
|
27 |
+
*/
|
28 |
+
function __construct ($APIKey = "", $sharedSecret=""){
|
29 |
+
|
30 |
+
if (!empty($APIKey))
|
31 |
+
{
|
32 |
+
$this->_secrets['consumer_key'] = $APIKey;
|
33 |
+
}
|
34 |
+
|
35 |
+
if (!empty($sharedSecret))
|
36 |
+
{
|
37 |
+
$this->_secrets['shared_secret'] = $sharedSecret;
|
38 |
+
}
|
39 |
+
|
40 |
+
$this->_default_signature_method = "HMAC-SHA1";
|
41 |
+
$this->_action = "GET";
|
42 |
+
$this->_nonce_chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
|
43 |
+
|
44 |
+
return $this;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Reset the parameters and URL
|
49 |
+
*
|
50 |
+
* @access public
|
51 |
+
* @return OAuthSimple (Object)
|
52 |
+
*/
|
53 |
+
public function reset() {
|
54 |
+
$this->_parameters = Array();
|
55 |
+
$this->path = NULL;
|
56 |
+
$this->sbs = NULL;
|
57 |
+
|
58 |
+
return $this;
|
59 |
+
}
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Set the parameters either from a hash or a string
|
63 |
+
*
|
64 |
+
* @access public
|
65 |
+
* @param(string, object) List of parameters for the call, this can either be a URI string (e.g. "foo=bar&gorp=banana" or an object/hash)
|
66 |
+
* @return OAuthSimple (Object)
|
67 |
+
*/
|
68 |
+
public function setParameters ($parameters=Array()) {
|
69 |
+
|
70 |
+
if (is_string($parameters))
|
71 |
+
{
|
72 |
+
$parameters = $this->_parseParameterString($parameters);
|
73 |
+
}
|
74 |
+
if (empty($this->_parameters))
|
75 |
+
{
|
76 |
+
$this->_parameters = $parameters;
|
77 |
+
}
|
78 |
+
else if (!empty($parameters))
|
79 |
+
{
|
80 |
+
$this->_parameters = array_merge($this->_parameters,$parameters);
|
81 |
+
}
|
82 |
+
if (empty($this->_parameters['oauth_nonce']))
|
83 |
+
{
|
84 |
+
$this->_getNonce();
|
85 |
+
}
|
86 |
+
if (empty($this->_parameters['oauth_timestamp']))
|
87 |
+
{
|
88 |
+
$this->_getTimeStamp();
|
89 |
+
}
|
90 |
+
if (empty($this->_parameters['oauth_consumer_key']))
|
91 |
+
{
|
92 |
+
$this->_getApiKey();
|
93 |
+
}
|
94 |
+
if (empty($this->_parameters['oauth_token']))
|
95 |
+
{
|
96 |
+
$this->_getAccessToken();
|
97 |
+
}
|
98 |
+
if (empty($this->_parameters['oauth_signature_method']))
|
99 |
+
{
|
100 |
+
$this->setSignatureMethod();
|
101 |
+
}
|
102 |
+
if (empty($this->_parameters['oauth_version']))
|
103 |
+
{
|
104 |
+
$this->_parameters['oauth_version']="1.0";
|
105 |
+
}
|
106 |
+
|
107 |
+
return $this;
|
108 |
+
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Convenience method for setParameters
|
112 |
+
*
|
113 |
+
* @access public
|
114 |
+
* @see setParameters
|
115 |
+
*/
|
116 |
+
public function setQueryString ($parameters)
|
117 |
+
{
|
118 |
+
return $this->setParameters($parameters);
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Set the target URL (does not include the parameters)
|
123 |
+
*
|
124 |
+
* @param path (String) the fully qualified URI (excluding query arguments) (e.g "http://example.org/foo")
|
125 |
+
* @return OAuthSimple (Object)
|
126 |
+
*/
|
127 |
+
public function setURL ($path)
|
128 |
+
{
|
129 |
+
if (empty($path))
|
130 |
+
{
|
131 |
+
throw new OAuthSimpleException('No path specified for OAuthSimple.setURL');
|
132 |
+
}
|
133 |
+
$this->_path=$path;
|
134 |
+
|
135 |
+
return $this;
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Convenience method for setURL
|
140 |
+
*
|
141 |
+
* @param path (String)
|
142 |
+
* @see setURL
|
143 |
+
*/
|
144 |
+
public function setPath ($path)
|
145 |
+
{
|
146 |
+
return $this->_path=$path;
|
147 |
+
}
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Set the "action" for the url, (e.g. GET,POST, DELETE, etc.)
|
151 |
+
*
|
152 |
+
* @param action (String) HTTP Action word.
|
153 |
+
* @return OAuthSimple (Object)
|
154 |
+
*/
|
155 |
+
public function setAction ($action)
|
156 |
+
{
|
157 |
+
if (empty($action))
|
158 |
+
{
|
159 |
+
$action = 'GET';
|
160 |
+
}
|
161 |
+
$action = strtoupper($action);
|
162 |
+
if (preg_match('/[^A-Z]/',$action))
|
163 |
+
{
|
164 |
+
throw new OAuthSimpleException('Invalid action specified for OAuthSimple.setAction');
|
165 |
+
}
|
166 |
+
$this->_action = $action;
|
167 |
+
|
168 |
+
return $this;
|
169 |
+
}
|
170 |
+
|
171 |
+
/**
|
172 |
+
* Set the signatures (as well as validate the ones you have)
|
173 |
+
*
|
174 |
+
* @param signatures (object) object/hash of the token/signature pairs {api_key:, shared_secret:, oauth_token: oauth_secret:}
|
175 |
+
* @return OAuthSimple (Object)
|
176 |
+
*/
|
177 |
+
public function signatures ($signatures)
|
178 |
+
{
|
179 |
+
if (!empty($signatures) && !is_array($signatures))
|
180 |
+
{
|
181 |
+
throw new OAuthSimpleException('Must pass dictionary array to OAuthSimple.signatures');
|
182 |
+
}
|
183 |
+
if (!empty($signatures))
|
184 |
+
{
|
185 |
+
if (empty($this->_secrets))
|
186 |
+
{
|
187 |
+
$this->_secrets=Array();
|
188 |
+
}
|
189 |
+
$this->_secrets=array_merge($this->_secrets,$signatures);
|
190 |
+
}
|
191 |
+
if (isset($this->_secrets['api_key']))
|
192 |
+
{
|
193 |
+
$this->_secrets['consumer_key'] = $this->_secrets['api_key'];
|
194 |
+
}
|
195 |
+
if (isset($this->_secrets['access_token']))
|
196 |
+
{
|
197 |
+
$this->_secrets['oauth_token'] = $this->_secrets['access_token'];
|
198 |
+
}
|
199 |
+
if (isset($this->_secrets['access_secret']))
|
200 |
+
{
|
201 |
+
$this->_secrets['oauth_secret'] = $this->_secrets['access_secret'];
|
202 |
+
}
|
203 |
+
if (isset($this->_secrets['access_token_secret']))
|
204 |
+
{
|
205 |
+
$this->_secrets['oauth_secret'] = $this->_secrets['access_token_secret'];
|
206 |
+
}
|
207 |
+
if (empty($this->_secrets['consumer_key']))
|
208 |
+
{
|
209 |
+
throw new OAuthSimpleException('Missing required consumer_key in OAuthSimple.signatures');
|
210 |
+
}
|
211 |
+
if (empty($this->_secrets['shared_secret']))
|
212 |
+
{
|
213 |
+
throw new OAuthSimpleException('Missing requires shared_secret in OAuthSimple.signatures');
|
214 |
+
}
|
215 |
+
if (!empty($this->_secrets['oauth_token']) && empty($this->_secrets['oauth_secret']))
|
216 |
+
{
|
217 |
+
throw new OAuthSimpleException('Missing oauth_secret for supplied oauth_token in OAuthSimple.signatures');
|
218 |
+
}
|
219 |
+
|
220 |
+
return $this;
|
221 |
+
}
|
222 |
+
|
223 |
+
public function setTokensAndSecrets($signatures)
|
224 |
+
{
|
225 |
+
return $this->signatures($signatures);
|
226 |
+
}
|
227 |
+
|
228 |
+
/**
|
229 |
+
* Set the signature method (currently only Plaintext or SHA-MAC1)
|
230 |
+
*
|
231 |
+
* @param method (String) Method of signing the transaction (only PLAINTEXT and SHA-MAC1 allowed for now)
|
232 |
+
* @return OAuthSimple (Object)
|
233 |
+
*/
|
234 |
+
public function setSignatureMethod ($method="")
|
235 |
+
{
|
236 |
+
if (empty($method))
|
237 |
+
{
|
238 |
+
$method = $this->_default_signature_method;
|
239 |
+
}
|
240 |
+
$method = strtoupper($method);
|
241 |
+
switch($method)
|
242 |
+
{
|
243 |
+
case 'PLAINTEXT':
|
244 |
+
case 'HMAC-SHA1':
|
245 |
+
$this->_parameters['oauth_signature_method']=$method;
|
246 |
+
break;
|
247 |
+
default:
|
248 |
+
throw new OAuthSimpleException ("Unknown signing method $method specified for OAuthSimple.setSignatureMethod");
|
249 |
+
break;
|
250 |
+
}
|
251 |
+
|
252 |
+
return $this;
|
253 |
+
}
|
254 |
+
|
255 |
+
/** sign the request
|
256 |
+
*
|
257 |
+
* note: all arguments are optional, provided you've set them using the
|
258 |
+
* other helper functions.
|
259 |
+
*
|
260 |
+
* @param args (Array) hash of arguments for the call {action, path, parameters (array), method, signatures (array)} all arguments are optional.
|
261 |
+
* @return (Array) signed values
|
262 |
+
*/
|
263 |
+
public function sign($args=array())
|
264 |
+
{
|
265 |
+
if (!empty($args['action']))
|
266 |
+
{
|
267 |
+
$this->setAction($args['action']);
|
268 |
+
}
|
269 |
+
if (!empty($args['path']))
|
270 |
+
{
|
271 |
+
$this->setPath($args['path']);
|
272 |
+
}
|
273 |
+
if (!empty($args['method']))
|
274 |
+
{
|
275 |
+
$this->setSignatureMethod($args['method']);
|
276 |
+
}
|
277 |
+
if (!empty($args['signatures']))
|
278 |
+
{
|
279 |
+
$this->signatures($args['signatures']);
|
280 |
+
}
|
281 |
+
if (empty($args['parameters']))
|
282 |
+
{
|
283 |
+
$args['parameters']=array();
|
284 |
+
}
|
285 |
+
$this->setParameters($args['parameters']);
|
286 |
+
$normParams = $this->_normalizedParameters();
|
287 |
+
$this->_parameters['oauth_signature'] = $this->_generateSignature($normParams);
|
288 |
+
|
289 |
+
return Array (
|
290 |
+
'parameters' => $this->_parameters,
|
291 |
+
'signature' => self::_oauthEscape($this->_parameters['oauth_signature']),
|
292 |
+
'signed_url' => $this->_path . '?' . $this->_normalizedParameters(),
|
293 |
+
'header' => $this->getHeaderString(),
|
294 |
+
'sbs'=> $this->sbs
|
295 |
+
);
|
296 |
+
}
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Return a formatted "header" string
|
300 |
+
*
|
301 |
+
* NOTE: This doesn't set the "Authorization: " prefix, which is required.
|
302 |
+
* It's not set because various set header functions prefer different
|
303 |
+
* ways to do that.
|
304 |
+
*
|
305 |
+
* @param args (Array)
|
306 |
+
* @return $result (String)
|
307 |
+
*/
|
308 |
+
public function getHeaderString ($args=array())
|
309 |
+
{
|
310 |
+
if (empty($this->_parameters['oauth_signature']))
|
311 |
+
{
|
312 |
+
$this->sign($args);
|
313 |
+
}
|
314 |
+
$result = 'OAuth ';
|
315 |
+
|
316 |
+
foreach ($this->_parameters as $pName => $pValue)
|
317 |
+
{
|
318 |
+
if (strpos($pName,'oauth_') !== 0 || $pName == 'oauth_token_secret2')
|
319 |
+
{
|
320 |
+
continue;
|
321 |
+
}
|
322 |
+
if (is_array($pValue))
|
323 |
+
{
|
324 |
+
foreach ($pValue as $val)
|
325 |
+
{
|
326 |
+
$result .= $pName .'="' . self::_oauthEscape($val) . '", ';
|
327 |
+
}
|
328 |
+
}
|
329 |
+
else
|
330 |
+
{
|
331 |
+
$result .= $pName . '="' . self::_oauthEscape($pValue) . '", ';
|
332 |
+
}
|
333 |
+
}
|
334 |
+
|
335 |
+
return preg_replace('/, $/','',$result);
|
336 |
+
}
|
337 |
+
|
338 |
+
private function _parseParameterString ($paramString)
|
339 |
+
{
|
340 |
+
$elements = explode('&',$paramString);
|
341 |
+
$result = array();
|
342 |
+
foreach ($elements as $element)
|
343 |
+
{
|
344 |
+
list ($key,$token) = explode('=',$element);
|
345 |
+
if ($token)
|
346 |
+
{
|
347 |
+
$token = urldecode($token);
|
348 |
+
}
|
349 |
+
if (!empty($result[$key]))
|
350 |
+
{
|
351 |
+
if (!is_array($result[$key]))
|
352 |
+
{
|
353 |
+
$result[$key] = array($result[$key],$token);
|
354 |
+
}
|
355 |
+
else
|
356 |
+
{
|
357 |
+
array_push($result[$key],$token);
|
358 |
+
}
|
359 |
+
}
|
360 |
+
else
|
361 |
+
$result[$key]=$token;
|
362 |
+
}
|
363 |
+
return $result;
|
364 |
+
}
|
365 |
+
|
366 |
+
|
367 |
+
private static function _oauthEscape($string)
|
368 |
+
{
|
369 |
+
if ($string === 0) { return 0; }
|
370 |
+
if ($string == '0') { return '0'; }
|
371 |
+
if (strlen($string) == 0) { return ''; }
|
372 |
+
if (is_array($string)) {
|
373 |
+
throw new OAuthSimpleException('Array passed to _oauthEscape');
|
374 |
+
}
|
375 |
+
$string = rawurlencode($string);
|
376 |
+
|
377 |
+
$string = str_replace('+','%20',$string);
|
378 |
+
$string = str_replace('!','%21',$string);
|
379 |
+
$string = str_replace('*','%2A',$string);
|
380 |
+
$string = str_replace('\'','%27',$string);
|
381 |
+
$string = str_replace('(','%28',$string);
|
382 |
+
$string = str_replace(')','%29',$string);
|
383 |
+
|
384 |
+
return $string;
|
385 |
+
}
|
386 |
+
|
387 |
+
private function _getNonce($length=5)
|
388 |
+
{
|
389 |
+
$result = '';
|
390 |
+
$cLength = strlen($this->_nonce_chars);
|
391 |
+
for ($i=0; $i < $length; $i++)
|
392 |
+
{
|
393 |
+
$rnum = rand(0,$cLength);
|
394 |
+
$result .= substr($this->_nonce_chars,$rnum,1);
|
395 |
+
}
|
396 |
+
$result = md5($result);
|
397 |
+
$this->_parameters['oauth_nonce'] = $result;
|
398 |
+
|
399 |
+
return $result;
|
400 |
+
}
|
401 |
+
|
402 |
+
private function _getApiKey()
|
403 |
+
{
|
404 |
+
if (empty($this->_secrets['consumer_key']))
|
405 |
+
{
|
406 |
+
throw new OAuthSimpleException('No consumer_key set for OAuthSimple');
|
407 |
+
}
|
408 |
+
$this->_parameters['oauth_consumer_key']=$this->_secrets['consumer_key'];
|
409 |
+
|
410 |
+
return $this->_parameters['oauth_consumer_key'];
|
411 |
+
}
|
412 |
+
|
413 |
+
private function _getAccessToken()
|
414 |
+
{
|
415 |
+
if (!isset($this->_secrets['oauth_secret']))
|
416 |
+
{
|
417 |
+
return '';
|
418 |
+
}
|
419 |
+
if (!isset($this->_secrets['oauth_token']))
|
420 |
+
{
|
421 |
+
throw new OAuthSimpleException('No access token (oauth_token) set for OAuthSimple.');
|
422 |
+
}
|
423 |
+
$this->_parameters['oauth_token'] = $this->_secrets['oauth_token'];
|
424 |
+
|
425 |
+
return $this->_parameters['oauth_token'];
|
426 |
+
}
|
427 |
+
|
428 |
+
private function _getTimeStamp()
|
429 |
+
{
|
430 |
+
return $this->_parameters['oauth_timestamp'] = time();
|
431 |
+
}
|
432 |
+
|
433 |
+
private function _normalizedParameters()
|
434 |
+
{
|
435 |
+
$normalized_keys = array();
|
436 |
+
$return_array = array();
|
437 |
+
|
438 |
+
foreach ( $this->_parameters as $paramName=>$paramValue) {
|
439 |
+
if (!preg_match('/\w+_secret/',$paramName) OR (strpos($paramValue, '@') !== 0 && !file_exists(substr($paramValue, 1))) )
|
440 |
+
{
|
441 |
+
if (is_array($paramValue))
|
442 |
+
{
|
443 |
+
$normalized_keys[self::_oauthEscape($paramName)] = array();
|
444 |
+
foreach($paramValue as $item)
|
445 |
+
{
|
446 |
+
array_push($normalized_keys[self::_oauthEscape($paramName)], self::_oauthEscape($item));
|
447 |
+
}
|
448 |
+
}
|
449 |
+
else
|
450 |
+
{
|
451 |
+
$normalized_keys[self::_oauthEscape($paramName)] = self::_oauthEscape($paramValue);
|
452 |
+
}
|
453 |
+
}
|
454 |
+
}
|
455 |
+
|
456 |
+
ksort($normalized_keys);
|
457 |
+
|
458 |
+
foreach($normalized_keys as $key=>$val)
|
459 |
+
{
|
460 |
+
if (is_array($val))
|
461 |
+
{
|
462 |
+
sort($val);
|
463 |
+
foreach($val as $element)
|
464 |
+
{
|
465 |
+
array_push($return_array, $key . "=" . $element);
|
466 |
+
}
|
467 |
+
}
|
468 |
+
else
|
469 |
+
{
|
470 |
+
array_push($return_array, $key .'='. $val);
|
471 |
+
}
|
472 |
+
|
473 |
+
}
|
474 |
+
|
475 |
+
return join("&", $return_array);
|
476 |
+
}
|
477 |
+
|
478 |
+
|
479 |
+
private function _generateSignature ()
|
480 |
+
{
|
481 |
+
$secretKey = '';
|
482 |
+
if(isset($this->_secrets['shared_secret']))
|
483 |
+
{
|
484 |
+
$secretKey = self::_oauthEscape($this->_secrets['shared_secret']);
|
485 |
+
}
|
486 |
+
|
487 |
+
$secretKey .= '&';
|
488 |
+
if(isset($this->_secrets['oauth_secret']))
|
489 |
+
{
|
490 |
+
$secretKey .= self::_oauthEscape($this->_secrets['oauth_secret']);
|
491 |
+
}
|
492 |
+
|
493 |
+
switch($this->_parameters['oauth_signature_method'])
|
494 |
+
{
|
495 |
+
case 'PLAINTEXT':
|
496 |
+
return urlencode($secretKey);;
|
497 |
+
case 'HMAC-SHA1':
|
498 |
+
$this->sbs = self::_oauthEscape($this->_action).'&'.self::_oauthEscape($this->_path).'&'.self::_oauthEscape($this->_normalizedParameters());
|
499 |
+
|
500 |
+
return base64_encode(hash_hmac('sha1',$this->sbs,$secretKey,TRUE));
|
501 |
+
default:
|
502 |
+
throw new OAuthSimpleException('Unknown signature method for OAuthSimple');
|
503 |
+
break;
|
504 |
+
}
|
505 |
+
}
|
506 |
+
}
|
507 |
+
|
508 |
+
class OAuthSimpleException extends Exception {
|
509 |
+
|
510 |
+
public function __construct($err, $isDebug = FALSE)
|
511 |
+
{
|
512 |
+
self::log_error($err);
|
513 |
+
if ($isDebug)
|
514 |
+
{
|
515 |
+
self::display_error($err, TRUE);
|
516 |
+
}
|
517 |
+
}
|
518 |
+
|
519 |
+
public static function log_error($err)
|
520 |
+
{
|
521 |
+
error_log($err, 0);
|
522 |
+
}
|
523 |
+
|
524 |
+
public static function display_error($err, $kill = FALSE)
|
525 |
+
{
|
526 |
+
print_r($err);
|
527 |
+
if ($kill === FALSE)
|
528 |
+
{
|
529 |
+
die();
|
530 |
+
}
|
531 |
+
}
|
532 |
+
}
|
classes/fileRecursion.php
CHANGED
@@ -432,8 +432,14 @@ class fileRecursion{
|
|
432 |
* @return
|
433 |
*/
|
434 |
public static function getDirectories($dir){
|
435 |
-
|
|
|
436 |
self::debug("Processing $dir");
|
|
|
|
|
|
|
|
|
|
|
437 |
|
438 |
if(is_dir($dir)) {
|
439 |
self::debug("OK directory $dir");
|
432 |
* @return
|
433 |
*/
|
434 |
public static function getDirectories($dir){
|
435 |
+
global $_CONFIG;
|
436 |
+
|
437 |
self::debug("Processing $dir");
|
438 |
+
|
439 |
+
if(!stristr(realpath($dir), realpath($_CONFIG['backup_path']))){
|
440 |
+
|
441 |
+
return false;
|
442 |
+
}
|
443 |
|
444 |
if(is_dir($dir)) {
|
445 |
self::debug("OK directory $dir");
|
classes/mysqlBackup.class.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
/*
|
3 |
* mysqlBackup.class.php
|
4 |
*
|
5 |
-
* Copyright
|
6 |
*
|
7 |
* This program is free software; you can redistribute it and/or modify
|
8 |
* it under the terms of the GNU General Public License as published by
|
@@ -105,16 +105,10 @@ class DB{
|
|
105 |
*/
|
106 |
public function connect(){
|
107 |
|
108 |
-
self::$link =
|
109 |
-
if (
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
if(self::$dbDatabase != ""){
|
114 |
-
self::$db_selected = mysql_select_db(self::$dbDatabase, self::$link);
|
115 |
-
if (!self::$db_selected) {
|
116 |
-
self::error ('Can\'t use foo : ' . mysql_error());
|
117 |
-
}
|
118 |
}
|
119 |
|
120 |
}
|
@@ -128,7 +122,7 @@ class DB{
|
|
128 |
*/
|
129 |
public function disconnect(){
|
130 |
|
131 |
-
|
132 |
|
133 |
}
|
134 |
|
@@ -143,7 +137,7 @@ class DB{
|
|
143 |
|
144 |
self::query("SET SQL_QUOTE_SHOW_CREATE=1;");
|
145 |
self::query("SET sql_mode = 0;");
|
146 |
-
|
147 |
if (self::$dbCompatibility)
|
148 |
self::query("SET sql_mode=" . self::$dbCompatibility . ";");
|
149 |
|
@@ -158,11 +152,11 @@ class DB{
|
|
158 |
*/
|
159 |
public function query($query){
|
160 |
|
161 |
-
$result =
|
162 |
self::error($query, 1);
|
163 |
|
164 |
if (!$result) {
|
165 |
-
self::error('Invalid query: ' .
|
166 |
return false;
|
167 |
}
|
168 |
else{
|
@@ -186,7 +180,7 @@ class DB{
|
|
186 |
|
187 |
$result = self::query("SHOW TABLES in `".self::$dbDatabase."`");
|
188 |
|
189 |
-
while ($row =
|
190 |
$tablesList[$inc]['table'] = $row[0];
|
191 |
|
192 |
if(is_array($excluded))
|
@@ -243,7 +237,7 @@ class DB{
|
|
243 |
|
244 |
$result = self::query("SELECT count(*) FROM $table;");
|
245 |
|
246 |
-
$count =
|
247 |
|
248 |
return intval($count[0]) ;// not max limit on 32 bit systems 2147483647; on 64 bit 9223372036854775807
|
249 |
|
@@ -315,7 +309,7 @@ class DB{
|
|
315 |
$return['totalRecords'] = $tableInfo[1];
|
316 |
|
317 |
//if(intval($return['totalRecords']) != 0)
|
318 |
-
if(trim($tableName) !=
|
319 |
self::exportTable($databaseName, $tableName, $startAtRecord, self::$recordsPerSession, $fd);
|
320 |
|
321 |
fclose($fd);
|
@@ -390,7 +384,7 @@ class DB{
|
|
390 |
|
391 |
$result = self::query("SELECT * from `$databaseName`.`$tableName` Limit $start, $limit ;");
|
392 |
if($result){
|
393 |
-
while($row =
|
394 |
|
395 |
fwrite($fd, "INSERT INTO `$tableName` VALUES (");
|
396 |
$arr = $row;
|
@@ -398,7 +392,7 @@ class DB{
|
|
398 |
self::$countRecords++;
|
399 |
|
400 |
foreach ($arr as $key => $value) {
|
401 |
-
$value =
|
402 |
$buffer .= "'".$value."', ";
|
403 |
}
|
404 |
$buffer = rtrim($buffer, ', ') . ");\n";
|
@@ -419,7 +413,7 @@ class DB{
|
|
419 |
|
420 |
$result = self::query("SHOW CREATE table `$databaseName`.`$tableName`;");
|
421 |
if($result){
|
422 |
-
$row =
|
423 |
fwrite($fd, $row[1].";\n");
|
424 |
}
|
425 |
|
@@ -470,7 +464,7 @@ class DB{
|
|
470 |
|
471 |
$result = self::query("SHOW VARIABLES LIKE \"%version%\";");
|
472 |
if($result){
|
473 |
-
while($row =
|
474 |
|
475 |
$return .= "# MYSQL ".$row[0].": ".$row[1]."\n";
|
476 |
|
@@ -484,5 +478,3 @@ class DB{
|
|
484 |
|
485 |
|
486 |
}
|
487 |
-
|
488 |
-
?>
|
2 |
/*
|
3 |
* mysqlBackup.class.php
|
4 |
*
|
5 |
+
* Copyright 2014 Ovidiu Liuta <info@thinkovi.com>
|
6 |
*
|
7 |
* This program is free software; you can redistribute it and/or modify
|
8 |
* it under the terms of the GNU General Public License as published by
|
105 |
*/
|
106 |
public function connect(){
|
107 |
|
108 |
+
self::$link = new mysqli(self::$dbHostname, self::$dbUsername, self::$dbPassword, self::$dbDatabase);
|
109 |
+
if (mysqli_connect_errno()) {
|
110 |
+
printf("Connect failed: %s\n", mysqli_connect_error());
|
111 |
+
exit();
|
|
|
|
|
|
|
|
|
|
|
|
|
112 |
}
|
113 |
|
114 |
}
|
122 |
*/
|
123 |
public function disconnect(){
|
124 |
|
125 |
+
//mysqli_close(self::$link);
|
126 |
|
127 |
}
|
128 |
|
137 |
|
138 |
self::query("SET SQL_QUOTE_SHOW_CREATE=1;");
|
139 |
self::query("SET sql_mode = 0;");
|
140 |
+
mysqli_set_charset(self::$link, 'utf8');
|
141 |
if (self::$dbCompatibility)
|
142 |
self::query("SET sql_mode=" . self::$dbCompatibility . ";");
|
143 |
|
152 |
*/
|
153 |
public function query($query){
|
154 |
|
155 |
+
$result = mysqli_query(self::$link, $query.";");
|
156 |
self::error($query, 1);
|
157 |
|
158 |
if (!$result) {
|
159 |
+
self::error('Invalid query: ' . mysqli_error());
|
160 |
return false;
|
161 |
}
|
162 |
else{
|
180 |
|
181 |
$result = self::query("SHOW TABLES in `".self::$dbDatabase."`");
|
182 |
|
183 |
+
while ($row = mysqli_fetch_array( $result)){
|
184 |
$tablesList[$inc]['table'] = $row[0];
|
185 |
|
186 |
if(is_array($excluded))
|
237 |
|
238 |
$result = self::query("SELECT count(*) FROM $table;");
|
239 |
|
240 |
+
$count = mysqli_fetch_row($result);
|
241 |
|
242 |
return intval($count[0]) ;// not max limit on 32 bit systems 2147483647; on 64 bit 9223372036854775807
|
243 |
|
309 |
$return['totalRecords'] = $tableInfo[1];
|
310 |
|
311 |
//if(intval($return['totalRecords']) != 0)
|
312 |
+
if(trim($tableName) !="" and !$tableInfo[2])
|
313 |
self::exportTable($databaseName, $tableName, $startAtRecord, self::$recordsPerSession, $fd);
|
314 |
|
315 |
fclose($fd);
|
384 |
|
385 |
$result = self::query("SELECT * from `$databaseName`.`$tableName` Limit $start, $limit ;");
|
386 |
if($result){
|
387 |
+
while($row = mysqli_fetch_array($result, MYSQL_ASSOC)){
|
388 |
|
389 |
fwrite($fd, "INSERT INTO `$tableName` VALUES (");
|
390 |
$arr = $row;
|
392 |
self::$countRecords++;
|
393 |
|
394 |
foreach ($arr as $key => $value) {
|
395 |
+
$value = mysqli_real_escape_string(self::$link, $value);
|
396 |
$buffer .= "'".$value."', ";
|
397 |
}
|
398 |
$buffer = rtrim($buffer, ', ') . ");\n";
|
413 |
|
414 |
$result = self::query("SHOW CREATE table `$databaseName`.`$tableName`;");
|
415 |
if($result){
|
416 |
+
$row = mysqli_fetch_row( $result);
|
417 |
fwrite($fd, $row[1].";\n");
|
418 |
}
|
419 |
|
464 |
|
465 |
$result = self::query("SHOW VARIABLES LIKE \"%version%\";");
|
466 |
if($result){
|
467 |
+
while($row = mysqli_fetch_array($result)){
|
468 |
|
469 |
$return .= "# MYSQL ".$row[0].": ".$row[1]."\n";
|
470 |
|
478 |
|
479 |
|
480 |
}
|
|
|
|
classes/phpseclib/Crypt/AES.php
ADDED
@@ -0,0 +1,594 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of AES.
|
6 |
+
*
|
7 |
+
* Uses mcrypt, if available, and an internal implementation, otherwise.
|
8 |
+
*
|
9 |
+
* PHP versions 4 and 5
|
10 |
+
*
|
11 |
+
* If {@link Crypt_AES::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
|
12 |
+
* {@link Crypt_AES::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's 136-bits
|
13 |
+
* it'll be null-padded to 160-bits and 160 bits will be the key length until {@link Crypt_Rijndael::setKey() setKey()}
|
14 |
+
* is called, again, at which point, it'll be recalculated.
|
15 |
+
*
|
16 |
+
* Since Crypt_AES extends Crypt_Rijndael, some functions are available to be called that, in the context of AES, don't
|
17 |
+
* make a whole lot of sense. {@link Crypt_AES::setBlockLength() setBlockLength()}, for instance. Calling that function,
|
18 |
+
* however possible, won't do anything (AES has a fixed block length whereas Rijndael has a variable one).
|
19 |
+
*
|
20 |
+
* Here's a short example of how to use this library:
|
21 |
+
* <code>
|
22 |
+
* <?php
|
23 |
+
* include('Crypt/AES.php');
|
24 |
+
*
|
25 |
+
* $aes = new Crypt_AES();
|
26 |
+
*
|
27 |
+
* $aes->setKey('abcdefghijklmnop');
|
28 |
+
*
|
29 |
+
* $size = 10 * 1024;
|
30 |
+
* $plaintext = '';
|
31 |
+
* for ($i = 0; $i < $size; $i++) {
|
32 |
+
* $plaintext.= 'a';
|
33 |
+
* }
|
34 |
+
*
|
35 |
+
* echo $aes->decrypt($aes->encrypt($plaintext));
|
36 |
+
* ?>
|
37 |
+
* </code>
|
38 |
+
*
|
39 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
40 |
+
* of this software and associated documentation files (the "Software"), to deal
|
41 |
+
* in the Software without restriction, including without limitation the rights
|
42 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
43 |
+
* copies of the Software, and to permit persons to whom the Software is
|
44 |
+
* furnished to do so, subject to the following conditions:
|
45 |
+
*
|
46 |
+
* The above copyright notice and this permission notice shall be included in
|
47 |
+
* all copies or substantial portions of the Software.
|
48 |
+
*
|
49 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
50 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
51 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
52 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
53 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
54 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
55 |
+
* THE SOFTWARE.
|
56 |
+
*
|
57 |
+
* @category Crypt
|
58 |
+
* @package Crypt_AES
|
59 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
60 |
+
* @copyright MMVIII Jim Wigginton
|
61 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
62 |
+
* @version $Id: AES.php,v 1.7 2010/02/09 06:10:25 terrafrost Exp $
|
63 |
+
* @link http://phpseclib.sourceforge.net
|
64 |
+
*/
|
65 |
+
|
66 |
+
/**
|
67 |
+
* Include Crypt_Rijndael
|
68 |
+
*/
|
69 |
+
require_once 'Rijndael.php';
|
70 |
+
|
71 |
+
/**#@+
|
72 |
+
* @access public
|
73 |
+
* @see Crypt_AES::encrypt()
|
74 |
+
* @see Crypt_AES::decrypt()
|
75 |
+
*/
|
76 |
+
/**
|
77 |
+
* Encrypt / decrypt using the Counter mode.
|
78 |
+
*
|
79 |
+
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
|
80 |
+
*
|
81 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
|
82 |
+
*/
|
83 |
+
define('CRYPT_AES_MODE_CTR', -1);
|
84 |
+
/**
|
85 |
+
* Encrypt / decrypt using the Electronic Code Book mode.
|
86 |
+
*
|
87 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
|
88 |
+
*/
|
89 |
+
define('CRYPT_AES_MODE_ECB', 1);
|
90 |
+
/**
|
91 |
+
* Encrypt / decrypt using the Code Book Chaining mode.
|
92 |
+
*
|
93 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
|
94 |
+
*/
|
95 |
+
define('CRYPT_AES_MODE_CBC', 2);
|
96 |
+
/**
|
97 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
98 |
+
*
|
99 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
100 |
+
*/
|
101 |
+
define('CRYPT_AES_MODE_CFB', 3);
|
102 |
+
/**
|
103 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
104 |
+
*
|
105 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
|
106 |
+
*/
|
107 |
+
define('CRYPT_AES_MODE_OFB', 4);
|
108 |
+
/**#@-*/
|
109 |
+
|
110 |
+
/**#@+
|
111 |
+
* @access private
|
112 |
+
* @see Crypt_AES::Crypt_AES()
|
113 |
+
*/
|
114 |
+
/**
|
115 |
+
* Toggles the internal implementation
|
116 |
+
*/
|
117 |
+
define('CRYPT_AES_MODE_INTERNAL', 1);
|
118 |
+
/**
|
119 |
+
* Toggles the mcrypt implementation
|
120 |
+
*/
|
121 |
+
define('CRYPT_AES_MODE_MCRYPT', 2);
|
122 |
+
/**#@-*/
|
123 |
+
|
124 |
+
/**
|
125 |
+
* Pure-PHP implementation of AES.
|
126 |
+
*
|
127 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
128 |
+
* @version 0.1.0
|
129 |
+
* @access public
|
130 |
+
* @package Crypt_AES
|
131 |
+
*/
|
132 |
+
class Crypt_AES extends Crypt_Rijndael {
|
133 |
+
/**
|
134 |
+
* mcrypt resource for encryption
|
135 |
+
*
|
136 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
137 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
138 |
+
*
|
139 |
+
* @see Crypt_AES::encrypt()
|
140 |
+
* @var String
|
141 |
+
* @access private
|
142 |
+
*/
|
143 |
+
var $enmcrypt;
|
144 |
+
|
145 |
+
/**
|
146 |
+
* mcrypt resource for decryption
|
147 |
+
*
|
148 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
149 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
150 |
+
*
|
151 |
+
* @see Crypt_AES::decrypt()
|
152 |
+
* @var String
|
153 |
+
* @access private
|
154 |
+
*/
|
155 |
+
var $demcrypt;
|
156 |
+
|
157 |
+
/**
|
158 |
+
* mcrypt resource for CFB mode
|
159 |
+
*
|
160 |
+
* @see Crypt_AES::encrypt()
|
161 |
+
* @see Crypt_AES::decrypt()
|
162 |
+
* @var String
|
163 |
+
* @access private
|
164 |
+
*/
|
165 |
+
var $ecb;
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Default Constructor.
|
169 |
+
*
|
170 |
+
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
|
171 |
+
* CRYPT_AES_MODE_ECB or CRYPT_AES_MODE_CBC. If not explictly set, CRYPT_AES_MODE_CBC will be used.
|
172 |
+
*
|
173 |
+
* @param optional Integer $mode
|
174 |
+
* @return Crypt_AES
|
175 |
+
* @access public
|
176 |
+
*/
|
177 |
+
function Crypt_AES($mode = CRYPT_AES_MODE_CBC)
|
178 |
+
{
|
179 |
+
if ( !defined('CRYPT_AES_MODE') ) {
|
180 |
+
switch (true) {
|
181 |
+
case extension_loaded('mcrypt'):
|
182 |
+
// i'd check to see if aes was supported, by doing in_array('des', mcrypt_list_algorithms('')),
|
183 |
+
// but since that can be changed after the object has been created, there doesn't seem to be
|
184 |
+
// a lot of point...
|
185 |
+
define('CRYPT_AES_MODE', CRYPT_AES_MODE_MCRYPT);
|
186 |
+
break;
|
187 |
+
default:
|
188 |
+
define('CRYPT_AES_MODE', CRYPT_AES_MODE_INTERNAL);
|
189 |
+
}
|
190 |
+
}
|
191 |
+
|
192 |
+
switch ( CRYPT_AES_MODE ) {
|
193 |
+
case CRYPT_AES_MODE_MCRYPT:
|
194 |
+
switch ($mode) {
|
195 |
+
case CRYPT_AES_MODE_ECB:
|
196 |
+
$this->paddable = true;
|
197 |
+
$this->mode = MCRYPT_MODE_ECB;
|
198 |
+
break;
|
199 |
+
case CRYPT_AES_MODE_CTR:
|
200 |
+
// ctr doesn't have a constant associated with it even though it appears to be fairly widely
|
201 |
+
// supported. in lieu of knowing just how widely supported it is, i've, for now, opted not to
|
202 |
+
// include a compatibility layer. the layer has been implemented but, for now, is commented out.
|
203 |
+
$this->mode = 'ctr';
|
204 |
+
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_AES_MODE_CTR;
|
205 |
+
break;
|
206 |
+
case CRYPT_AES_MODE_CFB:
|
207 |
+
$this->mode = 'ncfb';
|
208 |
+
break;
|
209 |
+
case CRYPT_AES_MODE_OFB:
|
210 |
+
$this->mode = MCRYPT_MODE_NOFB;
|
211 |
+
break;
|
212 |
+
case CRYPT_AES_MODE_CBC:
|
213 |
+
default:
|
214 |
+
$this->paddable = true;
|
215 |
+
$this->mode = MCRYPT_MODE_CBC;
|
216 |
+
}
|
217 |
+
|
218 |
+
$this->debuffer = $this->enbuffer = '';
|
219 |
+
|
220 |
+
break;
|
221 |
+
default:
|
222 |
+
switch ($mode) {
|
223 |
+
case CRYPT_AES_MODE_ECB:
|
224 |
+
$this->paddable = true;
|
225 |
+
$this->mode = CRYPT_RIJNDAEL_MODE_ECB;
|
226 |
+
break;
|
227 |
+
case CRYPT_AES_MODE_CTR:
|
228 |
+
$this->mode = CRYPT_RIJNDAEL_MODE_CTR;
|
229 |
+
break;
|
230 |
+
case CRYPT_AES_MODE_CFB:
|
231 |
+
$this->mode = CRYPT_RIJNDAEL_MODE_CFB;
|
232 |
+
break;
|
233 |
+
case CRYPT_AES_MODE_OFB:
|
234 |
+
$this->mode = CRYPT_RIJNDAEL_MODE_OFB;
|
235 |
+
break;
|
236 |
+
case CRYPT_AES_MODE_CBC:
|
237 |
+
default:
|
238 |
+
$this->paddable = true;
|
239 |
+
$this->mode = CRYPT_RIJNDAEL_MODE_CBC;
|
240 |
+
}
|
241 |
+
}
|
242 |
+
|
243 |
+
if (CRYPT_AES_MODE == CRYPT_AES_MODE_INTERNAL) {
|
244 |
+
parent::Crypt_Rijndael($this->mode);
|
245 |
+
}
|
246 |
+
}
|
247 |
+
|
248 |
+
/**
|
249 |
+
* Dummy function
|
250 |
+
*
|
251 |
+
* Since Crypt_AES extends Crypt_Rijndael, this function is, technically, available, but it doesn't do anything.
|
252 |
+
*
|
253 |
+
* @access public
|
254 |
+
* @param Integer $length
|
255 |
+
*/
|
256 |
+
function setBlockLength($length)
|
257 |
+
{
|
258 |
+
return;
|
259 |
+
}
|
260 |
+
|
261 |
+
/**
|
262 |
+
* Encrypts a message.
|
263 |
+
*
|
264 |
+
* $plaintext will be padded with up to 16 additional bytes. Other AES implementations may or may not pad in the
|
265 |
+
* same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
|
266 |
+
* URL:
|
267 |
+
*
|
268 |
+
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
|
269 |
+
*
|
270 |
+
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
|
271 |
+
* strlen($plaintext) will still need to be a multiple of 16, however, arbitrary values can be added to make it that
|
272 |
+
* length.
|
273 |
+
*
|
274 |
+
* @see Crypt_AES::decrypt()
|
275 |
+
* @access public
|
276 |
+
* @param String $plaintext
|
277 |
+
*/
|
278 |
+
function encrypt($plaintext)
|
279 |
+
{
|
280 |
+
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
|
281 |
+
$changed = $this->changed;
|
282 |
+
$this->_mcryptSetup();
|
283 |
+
/*
|
284 |
+
if ($this->mode == CRYPT_AES_MODE_CTR) {
|
285 |
+
$iv = $this->encryptIV;
|
286 |
+
$xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($plaintext), $iv));
|
287 |
+
$ciphertext = $plaintext ^ $xor;
|
288 |
+
if ($this->continuousBuffer) {
|
289 |
+
$this->encryptIV = $iv;
|
290 |
+
}
|
291 |
+
return $ciphertext;
|
292 |
+
}
|
293 |
+
*/
|
294 |
+
// re: http://phpseclib.sourceforge.net/cfb-demo.phps
|
295 |
+
// using mcrypt's default handing of CFB the above would output two different things. using phpseclib's
|
296 |
+
// rewritten CFB implementation the above outputs the same thing twice.
|
297 |
+
if ($this->mode == 'ncfb') {
|
298 |
+
if ($changed) {
|
299 |
+
$this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
|
300 |
+
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
|
301 |
+
}
|
302 |
+
|
303 |
+
if (strlen($this->enbuffer)) {
|
304 |
+
$ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer));
|
305 |
+
$this->enbuffer.= $ciphertext;
|
306 |
+
if (strlen($this->enbuffer) == 16) {
|
307 |
+
$this->encryptIV = $this->enbuffer;
|
308 |
+
$this->enbuffer = '';
|
309 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
310 |
+
}
|
311 |
+
$plaintext = substr($plaintext, strlen($ciphertext));
|
312 |
+
} else {
|
313 |
+
$ciphertext = '';
|
314 |
+
}
|
315 |
+
|
316 |
+
$last_pos = strlen($plaintext) & 0xFFFFFFF0;
|
317 |
+
$ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : '';
|
318 |
+
|
319 |
+
if (strlen($plaintext) & 0xF) {
|
320 |
+
if (strlen($ciphertext)) {
|
321 |
+
$this->encryptIV = substr($ciphertext, -16);
|
322 |
+
}
|
323 |
+
$this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV);
|
324 |
+
$this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV;
|
325 |
+
$ciphertext.= $this->enbuffer;
|
326 |
+
}
|
327 |
+
|
328 |
+
return $ciphertext;
|
329 |
+
}
|
330 |
+
|
331 |
+
if ($this->paddable) {
|
332 |
+
$plaintext = $this->_pad($plaintext);
|
333 |
+
}
|
334 |
+
|
335 |
+
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
|
336 |
+
|
337 |
+
if (!$this->continuousBuffer) {
|
338 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
|
339 |
+
}
|
340 |
+
|
341 |
+
return $ciphertext;
|
342 |
+
}
|
343 |
+
|
344 |
+
return parent::encrypt($plaintext);
|
345 |
+
}
|
346 |
+
|
347 |
+
/**
|
348 |
+
* Decrypts a message.
|
349 |
+
*
|
350 |
+
* If strlen($ciphertext) is not a multiple of 16, null bytes will be added to the end of the string until it is.
|
351 |
+
*
|
352 |
+
* @see Crypt_AES::encrypt()
|
353 |
+
* @access public
|
354 |
+
* @param String $ciphertext
|
355 |
+
*/
|
356 |
+
function decrypt($ciphertext)
|
357 |
+
{
|
358 |
+
if ( CRYPT_AES_MODE == CRYPT_AES_MODE_MCRYPT ) {
|
359 |
+
$changed = $this->changed;
|
360 |
+
$this->_mcryptSetup();
|
361 |
+
/*
|
362 |
+
if ($this->mode == CRYPT_AES_MODE_CTR) {
|
363 |
+
$iv = $this->decryptIV;
|
364 |
+
$xor = mcrypt_generic($this->enmcrypt, $this->_generate_xor(strlen($ciphertext), $iv));
|
365 |
+
$plaintext = $ciphertext ^ $xor;
|
366 |
+
if ($this->continuousBuffer) {
|
367 |
+
$this->decryptIV = $iv;
|
368 |
+
}
|
369 |
+
return $plaintext;
|
370 |
+
}
|
371 |
+
*/
|
372 |
+
if ($this->mode == 'ncfb') {
|
373 |
+
if ($changed) {
|
374 |
+
$this->ecb = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, '');
|
375 |
+
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0");
|
376 |
+
}
|
377 |
+
|
378 |
+
if (strlen($this->debuffer)) {
|
379 |
+
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer));
|
380 |
+
|
381 |
+
$this->debuffer.= substr($ciphertext, 0, strlen($plaintext));
|
382 |
+
if (strlen($this->debuffer) == 16) {
|
383 |
+
$this->decryptIV = $this->debuffer;
|
384 |
+
$this->debuffer = '';
|
385 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
386 |
+
}
|
387 |
+
$ciphertext = substr($ciphertext, strlen($plaintext));
|
388 |
+
} else {
|
389 |
+
$plaintext = '';
|
390 |
+
}
|
391 |
+
|
392 |
+
$last_pos = strlen($ciphertext) & 0xFFFFFFF0;
|
393 |
+
$plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : '';
|
394 |
+
|
395 |
+
if (strlen($ciphertext) & 0xF) {
|
396 |
+
if (strlen($plaintext)) {
|
397 |
+
$this->decryptIV = substr($ciphertext, $last_pos - 16, 16);
|
398 |
+
}
|
399 |
+
$this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV);
|
400 |
+
$this->debuffer = substr($ciphertext, $last_pos);
|
401 |
+
$plaintext.= $this->debuffer ^ $this->decryptIV;
|
402 |
+
}
|
403 |
+
|
404 |
+
return $plaintext;
|
405 |
+
}
|
406 |
+
|
407 |
+
if ($this->paddable) {
|
408 |
+
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
|
409 |
+
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
410 |
+
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 15) & 0xFFFFFFF0, chr(0));
|
411 |
+
}
|
412 |
+
|
413 |
+
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
|
414 |
+
|
415 |
+
if (!$this->continuousBuffer) {
|
416 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
|
417 |
+
}
|
418 |
+
|
419 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
420 |
+
}
|
421 |
+
|
422 |
+
return parent::decrypt($ciphertext);
|
423 |
+
}
|
424 |
+
|
425 |
+
/**
|
426 |
+
* Setup mcrypt
|
427 |
+
*
|
428 |
+
* Validates all the variables.
|
429 |
+
*
|
430 |
+
* @access private
|
431 |
+
*/
|
432 |
+
function _mcryptSetup()
|
433 |
+
{
|
434 |
+
if (!$this->changed) {
|
435 |
+
return;
|
436 |
+
}
|
437 |
+
|
438 |
+
if (!$this->explicit_key_length) {
|
439 |
+
// this just copied from Crypt_Rijndael::_setup()
|
440 |
+
$length = strlen($this->key) >> 2;
|
441 |
+
if ($length > 8) {
|
442 |
+
$length = 8;
|
443 |
+
} else if ($length < 4) {
|
444 |
+
$length = 4;
|
445 |
+
}
|
446 |
+
$this->Nk = $length;
|
447 |
+
$this->key_size = $length << 2;
|
448 |
+
}
|
449 |
+
|
450 |
+
switch ($this->Nk) {
|
451 |
+
case 4: // 128
|
452 |
+
$this->key_size = 16;
|
453 |
+
break;
|
454 |
+
case 5: // 160
|
455 |
+
case 6: // 192
|
456 |
+
$this->key_size = 24;
|
457 |
+
break;
|
458 |
+
case 7: // 224
|
459 |
+
case 8: // 256
|
460 |
+
$this->key_size = 32;
|
461 |
+
}
|
462 |
+
|
463 |
+
$this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
|
464 |
+
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, 16), 16, chr(0));
|
465 |
+
|
466 |
+
if (!isset($this->enmcrypt)) {
|
467 |
+
$mode = $this->mode;
|
468 |
+
//$mode = $this->mode == CRYPT_AES_MODE_CTR ? MCRYPT_MODE_ECB : $this->mode;
|
469 |
+
|
470 |
+
$this->demcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
|
471 |
+
$this->enmcrypt = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', $mode, '');
|
472 |
+
} // else should mcrypt_generic_deinit be called?
|
473 |
+
|
474 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->iv);
|
475 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->iv);
|
476 |
+
|
477 |
+
$this->changed = false;
|
478 |
+
}
|
479 |
+
|
480 |
+
/**
|
481 |
+
* Encrypts a block
|
482 |
+
*
|
483 |
+
* Optimized over Crypt_Rijndael's implementation by means of loop unrolling.
|
484 |
+
*
|
485 |
+
* @see Crypt_Rijndael::_encryptBlock()
|
486 |
+
* @access private
|
487 |
+
* @param String $in
|
488 |
+
* @return String
|
489 |
+
*/
|
490 |
+
function _encryptBlock($in)
|
491 |
+
{
|
492 |
+
$state = unpack('N*word', $in);
|
493 |
+
|
494 |
+
$Nr = $this->Nr;
|
495 |
+
$w = $this->w;
|
496 |
+
$t0 = $this->t0;
|
497 |
+
$t1 = $this->t1;
|
498 |
+
$t2 = $this->t2;
|
499 |
+
$t3 = $this->t3;
|
500 |
+
|
501 |
+
// addRoundKey and reindex $state
|
502 |
+
$state = array(
|
503 |
+
$state['word1'] ^ $w[0][0],
|
504 |
+
$state['word2'] ^ $w[0][1],
|
505 |
+
$state['word3'] ^ $w[0][2],
|
506 |
+
$state['word4'] ^ $w[0][3]
|
507 |
+
);
|
508 |
+
|
509 |
+
// shiftRows + subWord + mixColumns + addRoundKey
|
510 |
+
// we could loop unroll this and use if statements to do more rounds as necessary, but, in my tests, that yields
|
511 |
+
// only a marginal improvement. since that also, imho, hinders the readability of the code, i've opted not to do it.
|
512 |
+
for ($round = 1; $round < $this->Nr; $round++) {
|
513 |
+
$state = array(
|
514 |
+
$t0[$state[0] & 0xFF000000] ^ $t1[$state[1] & 0x00FF0000] ^ $t2[$state[2] & 0x0000FF00] ^ $t3[$state[3] & 0x000000FF] ^ $w[$round][0],
|
515 |
+
$t0[$state[1] & 0xFF000000] ^ $t1[$state[2] & 0x00FF0000] ^ $t2[$state[3] & 0x0000FF00] ^ $t3[$state[0] & 0x000000FF] ^ $w[$round][1],
|
516 |
+
$t0[$state[2] & 0xFF000000] ^ $t1[$state[3] & 0x00FF0000] ^ $t2[$state[0] & 0x0000FF00] ^ $t3[$state[1] & 0x000000FF] ^ $w[$round][2],
|
517 |
+
$t0[$state[3] & 0xFF000000] ^ $t1[$state[0] & 0x00FF0000] ^ $t2[$state[1] & 0x0000FF00] ^ $t3[$state[2] & 0x000000FF] ^ $w[$round][3]
|
518 |
+
);
|
519 |
+
|
520 |
+
}
|
521 |
+
|
522 |
+
// subWord
|
523 |
+
$state = array(
|
524 |
+
$this->_subWord($state[0]),
|
525 |
+
$this->_subWord($state[1]),
|
526 |
+
$this->_subWord($state[2]),
|
527 |
+
$this->_subWord($state[3])
|
528 |
+
);
|
529 |
+
|
530 |
+
// shiftRows + addRoundKey
|
531 |
+
$state = array(
|
532 |
+
($state[0] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[3] & 0x000000FF) ^ $this->w[$this->Nr][0],
|
533 |
+
($state[1] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[0] & 0x000000FF) ^ $this->w[$this->Nr][1],
|
534 |
+
($state[2] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[1] & 0x000000FF) ^ $this->w[$this->Nr][2],
|
535 |
+
($state[3] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[2] & 0x000000FF) ^ $this->w[$this->Nr][3]
|
536 |
+
);
|
537 |
+
|
538 |
+
return pack('N*', $state[0], $state[1], $state[2], $state[3]);
|
539 |
+
}
|
540 |
+
|
541 |
+
/**
|
542 |
+
* Decrypts a block
|
543 |
+
*
|
544 |
+
* Optimized over Crypt_Rijndael's implementation by means of loop unrolling.
|
545 |
+
*
|
546 |
+
* @see Crypt_Rijndael::_decryptBlock()
|
547 |
+
* @access private
|
548 |
+
* @param String $in
|
549 |
+
* @return String
|
550 |
+
*/
|
551 |
+
function _decryptBlock($in)
|
552 |
+
{
|
553 |
+
$state = unpack('N*word', $in);
|
554 |
+
|
555 |
+
$Nr = $this->Nr;
|
556 |
+
$dw = $this->dw;
|
557 |
+
$dt0 = $this->dt0;
|
558 |
+
$dt1 = $this->dt1;
|
559 |
+
$dt2 = $this->dt2;
|
560 |
+
$dt3 = $this->dt3;
|
561 |
+
|
562 |
+
// addRoundKey and reindex $state
|
563 |
+
$state = array(
|
564 |
+
$state['word1'] ^ $dw[$this->Nr][0],
|
565 |
+
$state['word2'] ^ $dw[$this->Nr][1],
|
566 |
+
$state['word3'] ^ $dw[$this->Nr][2],
|
567 |
+
$state['word4'] ^ $dw[$this->Nr][3]
|
568 |
+
);
|
569 |
+
|
570 |
+
|
571 |
+
// invShiftRows + invSubBytes + invMixColumns + addRoundKey
|
572 |
+
for ($round = $this->Nr - 1; $round > 0; $round--) {
|
573 |
+
$state = array(
|
574 |
+
$dt0[$state[0] & 0xFF000000] ^ $dt1[$state[3] & 0x00FF0000] ^ $dt2[$state[2] & 0x0000FF00] ^ $dt3[$state[1] & 0x000000FF] ^ $dw[$round][0],
|
575 |
+
$dt0[$state[1] & 0xFF000000] ^ $dt1[$state[0] & 0x00FF0000] ^ $dt2[$state[3] & 0x0000FF00] ^ $dt3[$state[2] & 0x000000FF] ^ $dw[$round][1],
|
576 |
+
$dt0[$state[2] & 0xFF000000] ^ $dt1[$state[1] & 0x00FF0000] ^ $dt2[$state[0] & 0x0000FF00] ^ $dt3[$state[3] & 0x000000FF] ^ $dw[$round][2],
|
577 |
+
$dt0[$state[3] & 0xFF000000] ^ $dt1[$state[2] & 0x00FF0000] ^ $dt2[$state[1] & 0x0000FF00] ^ $dt3[$state[0] & 0x000000FF] ^ $dw[$round][3]
|
578 |
+
);
|
579 |
+
}
|
580 |
+
|
581 |
+
// invShiftRows + invSubWord + addRoundKey
|
582 |
+
$state = array(
|
583 |
+
$this->_invSubWord(($state[0] & 0xFF000000) ^ ($state[3] & 0x00FF0000) ^ ($state[2] & 0x0000FF00) ^ ($state[1] & 0x000000FF)) ^ $dw[0][0],
|
584 |
+
$this->_invSubWord(($state[1] & 0xFF000000) ^ ($state[0] & 0x00FF0000) ^ ($state[3] & 0x0000FF00) ^ ($state[2] & 0x000000FF)) ^ $dw[0][1],
|
585 |
+
$this->_invSubWord(($state[2] & 0xFF000000) ^ ($state[1] & 0x00FF0000) ^ ($state[0] & 0x0000FF00) ^ ($state[3] & 0x000000FF)) ^ $dw[0][2],
|
586 |
+
$this->_invSubWord(($state[3] & 0xFF000000) ^ ($state[2] & 0x00FF0000) ^ ($state[1] & 0x0000FF00) ^ ($state[0] & 0x000000FF)) ^ $dw[0][3]
|
587 |
+
);
|
588 |
+
|
589 |
+
return pack('N*', $state[0], $state[1], $state[2], $state[3]);
|
590 |
+
}
|
591 |
+
}
|
592 |
+
|
593 |
+
// vim: ts=4:sw=4:et:
|
594 |
+
// vim6: fdl=1:
|
classes/phpseclib/Crypt/DES.php
ADDED
@@ -0,0 +1,1245 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of DES.
|
6 |
+
*
|
7 |
+
* Uses mcrypt, if available, and an internal implementation, otherwise.
|
8 |
+
*
|
9 |
+
* PHP versions 4 and 5
|
10 |
+
*
|
11 |
+
* Useful resources are as follows:
|
12 |
+
*
|
13 |
+
* - {@link http://en.wikipedia.org/wiki/DES_supplementary_material Wikipedia: DES supplementary material}
|
14 |
+
* - {@link http://www.itl.nist.gov/fipspubs/fip46-2.htm FIPS 46-2 - (DES), Data Encryption Standard}
|
15 |
+
* - {@link http://www.cs.eku.edu/faculty/styer/460/Encrypt/JS-DES.html JavaScript DES Example}
|
16 |
+
*
|
17 |
+
* Here's a short example of how to use this library:
|
18 |
+
* <code>
|
19 |
+
* <?php
|
20 |
+
* include('Crypt/DES.php');
|
21 |
+
*
|
22 |
+
* $des = new Crypt_DES();
|
23 |
+
*
|
24 |
+
* $des->setKey('abcdefgh');
|
25 |
+
*
|
26 |
+
* $size = 10 * 1024;
|
27 |
+
* $plaintext = '';
|
28 |
+
* for ($i = 0; $i < $size; $i++) {
|
29 |
+
* $plaintext.= 'a';
|
30 |
+
* }
|
31 |
+
*
|
32 |
+
* echo $des->decrypt($des->encrypt($plaintext));
|
33 |
+
* ?>
|
34 |
+
* </code>
|
35 |
+
*
|
36 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
37 |
+
* of this software and associated documentation files (the "Software"), to deal
|
38 |
+
* in the Software without restriction, including without limitation the rights
|
39 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
40 |
+
* copies of the Software, and to permit persons to whom the Software is
|
41 |
+
* furnished to do so, subject to the following conditions:
|
42 |
+
*
|
43 |
+
* The above copyright notice and this permission notice shall be included in
|
44 |
+
* all copies or substantial portions of the Software.
|
45 |
+
*
|
46 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
47 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
48 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
49 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
50 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
51 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
52 |
+
* THE SOFTWARE.
|
53 |
+
*
|
54 |
+
* @category Crypt
|
55 |
+
* @package Crypt_DES
|
56 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
57 |
+
* @copyright MMVII Jim Wigginton
|
58 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
59 |
+
* @version $Id: DES.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
|
60 |
+
* @link http://phpseclib.sourceforge.net
|
61 |
+
*/
|
62 |
+
|
63 |
+
/**#@+
|
64 |
+
* @access private
|
65 |
+
* @see Crypt_DES::_prepareKey()
|
66 |
+
* @see Crypt_DES::_processBlock()
|
67 |
+
*/
|
68 |
+
/**
|
69 |
+
* Contains array_reverse($keys[CRYPT_DES_DECRYPT])
|
70 |
+
*/
|
71 |
+
define('CRYPT_DES_ENCRYPT', 0);
|
72 |
+
/**
|
73 |
+
* Contains array_reverse($keys[CRYPT_DES_ENCRYPT])
|
74 |
+
*/
|
75 |
+
define('CRYPT_DES_DECRYPT', 1);
|
76 |
+
/**#@-*/
|
77 |
+
|
78 |
+
/**#@+
|
79 |
+
* @access public
|
80 |
+
* @see Crypt_DES::encrypt()
|
81 |
+
* @see Crypt_DES::decrypt()
|
82 |
+
*/
|
83 |
+
/**
|
84 |
+
* Encrypt / decrypt using the Counter mode.
|
85 |
+
*
|
86 |
+
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
|
87 |
+
*
|
88 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
|
89 |
+
*/
|
90 |
+
define('CRYPT_DES_MODE_CTR', -1);
|
91 |
+
/**
|
92 |
+
* Encrypt / decrypt using the Electronic Code Book mode.
|
93 |
+
*
|
94 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
|
95 |
+
*/
|
96 |
+
define('CRYPT_DES_MODE_ECB', 1);
|
97 |
+
/**
|
98 |
+
* Encrypt / decrypt using the Code Book Chaining mode.
|
99 |
+
*
|
100 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
|
101 |
+
*/
|
102 |
+
define('CRYPT_DES_MODE_CBC', 2);
|
103 |
+
/**
|
104 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
105 |
+
*
|
106 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
107 |
+
*/
|
108 |
+
define('CRYPT_DES_MODE_CFB', 3);
|
109 |
+
/**
|
110 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
111 |
+
*
|
112 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
|
113 |
+
*/
|
114 |
+
define('CRYPT_DES_MODE_OFB', 4);
|
115 |
+
/**#@-*/
|
116 |
+
|
117 |
+
/**#@+
|
118 |
+
* @access private
|
119 |
+
* @see Crypt_DES::Crypt_DES()
|
120 |
+
*/
|
121 |
+
/**
|
122 |
+
* Toggles the internal implementation
|
123 |
+
*/
|
124 |
+
define('CRYPT_DES_MODE_INTERNAL', 1);
|
125 |
+
/**
|
126 |
+
* Toggles the mcrypt implementation
|
127 |
+
*/
|
128 |
+
define('CRYPT_DES_MODE_MCRYPT', 2);
|
129 |
+
/**#@-*/
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Pure-PHP implementation of DES.
|
133 |
+
*
|
134 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
135 |
+
* @version 0.1.0
|
136 |
+
* @access public
|
137 |
+
* @package Crypt_DES
|
138 |
+
*/
|
139 |
+
class Crypt_DES {
|
140 |
+
/**
|
141 |
+
* The Key Schedule
|
142 |
+
*
|
143 |
+
* @see Crypt_DES::setKey()
|
144 |
+
* @var Array
|
145 |
+
* @access private
|
146 |
+
*/
|
147 |
+
var $keys = "\0\0\0\0\0\0\0\0";
|
148 |
+
|
149 |
+
/**
|
150 |
+
* The Encryption Mode
|
151 |
+
*
|
152 |
+
* @see Crypt_DES::Crypt_DES()
|
153 |
+
* @var Integer
|
154 |
+
* @access private
|
155 |
+
*/
|
156 |
+
var $mode;
|
157 |
+
|
158 |
+
/**
|
159 |
+
* Continuous Buffer status
|
160 |
+
*
|
161 |
+
* @see Crypt_DES::enableContinuousBuffer()
|
162 |
+
* @var Boolean
|
163 |
+
* @access private
|
164 |
+
*/
|
165 |
+
var $continuousBuffer = false;
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Padding status
|
169 |
+
*
|
170 |
+
* @see Crypt_DES::enablePadding()
|
171 |
+
* @var Boolean
|
172 |
+
* @access private
|
173 |
+
*/
|
174 |
+
var $padding = true;
|
175 |
+
|
176 |
+
/**
|
177 |
+
* The Initialization Vector
|
178 |
+
*
|
179 |
+
* @see Crypt_DES::setIV()
|
180 |
+
* @var String
|
181 |
+
* @access private
|
182 |
+
*/
|
183 |
+
var $iv = "\0\0\0\0\0\0\0\0";
|
184 |
+
|
185 |
+
/**
|
186 |
+
* A "sliding" Initialization Vector
|
187 |
+
*
|
188 |
+
* @see Crypt_DES::enableContinuousBuffer()
|
189 |
+
* @var String
|
190 |
+
* @access private
|
191 |
+
*/
|
192 |
+
var $encryptIV = "\0\0\0\0\0\0\0\0";
|
193 |
+
|
194 |
+
/**
|
195 |
+
* A "sliding" Initialization Vector
|
196 |
+
*
|
197 |
+
* @see Crypt_DES::enableContinuousBuffer()
|
198 |
+
* @var String
|
199 |
+
* @access private
|
200 |
+
*/
|
201 |
+
var $decryptIV = "\0\0\0\0\0\0\0\0";
|
202 |
+
|
203 |
+
/**
|
204 |
+
* mcrypt resource for encryption
|
205 |
+
*
|
206 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
207 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
208 |
+
*
|
209 |
+
* @see Crypt_DES::encrypt()
|
210 |
+
* @var String
|
211 |
+
* @access private
|
212 |
+
*/
|
213 |
+
var $enmcrypt;
|
214 |
+
|
215 |
+
/**
|
216 |
+
* mcrypt resource for decryption
|
217 |
+
*
|
218 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
219 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
220 |
+
*
|
221 |
+
* @see Crypt_DES::decrypt()
|
222 |
+
* @var String
|
223 |
+
* @access private
|
224 |
+
*/
|
225 |
+
var $demcrypt;
|
226 |
+
|
227 |
+
/**
|
228 |
+
* Does the enmcrypt resource need to be (re)initialized?
|
229 |
+
*
|
230 |
+
* @see Crypt_DES::setKey()
|
231 |
+
* @see Crypt_DES::setIV()
|
232 |
+
* @var Boolean
|
233 |
+
* @access private
|
234 |
+
*/
|
235 |
+
var $enchanged = true;
|
236 |
+
|
237 |
+
/**
|
238 |
+
* Does the demcrypt resource need to be (re)initialized?
|
239 |
+
*
|
240 |
+
* @see Crypt_DES::setKey()
|
241 |
+
* @see Crypt_DES::setIV()
|
242 |
+
* @var Boolean
|
243 |
+
* @access private
|
244 |
+
*/
|
245 |
+
var $dechanged = true;
|
246 |
+
|
247 |
+
/**
|
248 |
+
* Is the mode one that is paddable?
|
249 |
+
*
|
250 |
+
* @see Crypt_DES::Crypt_DES()
|
251 |
+
* @var Boolean
|
252 |
+
* @access private
|
253 |
+
*/
|
254 |
+
var $paddable = false;
|
255 |
+
|
256 |
+
/**
|
257 |
+
* Encryption buffer for CTR, OFB and CFB modes
|
258 |
+
*
|
259 |
+
* @see Crypt_DES::encrypt()
|
260 |
+
* @var String
|
261 |
+
* @access private
|
262 |
+
*/
|
263 |
+
var $enbuffer = '';
|
264 |
+
|
265 |
+
/**
|
266 |
+
* Decryption buffer for CTR, OFB and CFB modes
|
267 |
+
*
|
268 |
+
* @see Crypt_DES::decrypt()
|
269 |
+
* @var String
|
270 |
+
* @access private
|
271 |
+
*/
|
272 |
+
var $debuffer = '';
|
273 |
+
|
274 |
+
/**
|
275 |
+
* mcrypt resource for CFB mode
|
276 |
+
*
|
277 |
+
* @see Crypt_DES::encrypt()
|
278 |
+
* @see Crypt_DES::decrypt()
|
279 |
+
* @var String
|
280 |
+
* @access private
|
281 |
+
*/
|
282 |
+
var $ecb;
|
283 |
+
|
284 |
+
/**
|
285 |
+
* Default Constructor.
|
286 |
+
*
|
287 |
+
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
|
288 |
+
* CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
|
289 |
+
*
|
290 |
+
* @param optional Integer $mode
|
291 |
+
* @return Crypt_DES
|
292 |
+
* @access public
|
293 |
+
*/
|
294 |
+
function Crypt_DES($mode = CRYPT_MODE_DES_CBC)
|
295 |
+
{
|
296 |
+
if ( !defined('CRYPT_DES_MODE') ) {
|
297 |
+
switch (true) {
|
298 |
+
case extension_loaded('mcrypt'):
|
299 |
+
// i'd check to see if des was supported, by doing in_array('des', mcrypt_list_algorithms('')),
|
300 |
+
// but since that can be changed after the object has been created, there doesn't seem to be
|
301 |
+
// a lot of point...
|
302 |
+
define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
|
303 |
+
break;
|
304 |
+
default:
|
305 |
+
define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
|
306 |
+
}
|
307 |
+
}
|
308 |
+
|
309 |
+
switch ( CRYPT_DES_MODE ) {
|
310 |
+
case CRYPT_DES_MODE_MCRYPT:
|
311 |
+
switch ($mode) {
|
312 |
+
case CRYPT_DES_MODE_ECB:
|
313 |
+
$this->paddable = true;
|
314 |
+
$this->mode = MCRYPT_MODE_ECB;
|
315 |
+
break;
|
316 |
+
case CRYPT_DES_MODE_CTR:
|
317 |
+
$this->mode = 'ctr';
|
318 |
+
//$this->mode = in_array('ctr', mcrypt_list_modes()) ? 'ctr' : CRYPT_DES_MODE_CTR;
|
319 |
+
break;
|
320 |
+
case CRYPT_DES_MODE_CFB:
|
321 |
+
$this->mode = 'ncfb';
|
322 |
+
break;
|
323 |
+
case CRYPT_DES_MODE_OFB:
|
324 |
+
$this->mode = MCRYPT_MODE_NOFB;
|
325 |
+
break;
|
326 |
+
case CRYPT_DES_MODE_CBC:
|
327 |
+
default:
|
328 |
+
$this->paddable = true;
|
329 |
+
$this->mode = MCRYPT_MODE_CBC;
|
330 |
+
}
|
331 |
+
|
332 |
+
break;
|
333 |
+
default:
|
334 |
+
switch ($mode) {
|
335 |
+
case CRYPT_DES_MODE_ECB:
|
336 |
+
case CRYPT_DES_MODE_CBC:
|
337 |
+
$this->paddable = true;
|
338 |
+
$this->mode = $mode;
|
339 |
+
break;
|
340 |
+
case CRYPT_DES_MODE_CTR:
|
341 |
+
case CRYPT_DES_MODE_CFB:
|
342 |
+
case CRYPT_DES_MODE_OFB:
|
343 |
+
$this->mode = $mode;
|
344 |
+
break;
|
345 |
+
default:
|
346 |
+
$this->paddable = true;
|
347 |
+
$this->mode = CRYPT_DES_MODE_CBC;
|
348 |
+
}
|
349 |
+
}
|
350 |
+
}
|
351 |
+
|
352 |
+
/**
|
353 |
+
* Sets the key.
|
354 |
+
*
|
355 |
+
* Keys can be of any length. DES, itself, uses 64-bit keys (eg. strlen($key) == 8), however, we
|
356 |
+
* only use the first eight, if $key has more then eight characters in it, and pad $key with the
|
357 |
+
* null byte if it is less then eight characters long.
|
358 |
+
*
|
359 |
+
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
|
360 |
+
*
|
361 |
+
* If the key is not explicitly set, it'll be assumed to be all zero's.
|
362 |
+
*
|
363 |
+
* @access public
|
364 |
+
* @param String $key
|
365 |
+
*/
|
366 |
+
function setKey($key)
|
367 |
+
{
|
368 |
+
$this->keys = ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) ? str_pad(substr($key, 0, 8), 8, chr(0)) : $this->_prepareKey($key);
|
369 |
+
$this->changed = true;
|
370 |
+
}
|
371 |
+
|
372 |
+
/**
|
373 |
+
* Sets the initialization vector. (optional)
|
374 |
+
*
|
375 |
+
* SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed
|
376 |
+
* to be all zero's.
|
377 |
+
*
|
378 |
+
* @access public
|
379 |
+
* @param String $iv
|
380 |
+
*/
|
381 |
+
function setIV($iv)
|
382 |
+
{
|
383 |
+
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
|
384 |
+
$this->changed = true;
|
385 |
+
}
|
386 |
+
|
387 |
+
/**
|
388 |
+
* Generate CTR XOR encryption key
|
389 |
+
*
|
390 |
+
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
|
391 |
+
* plaintext / ciphertext in CTR mode.
|
392 |
+
*
|
393 |
+
* @see Crypt_DES::decrypt()
|
394 |
+
* @see Crypt_DES::encrypt()
|
395 |
+
* @access public
|
396 |
+
* @param Integer $length
|
397 |
+
* @param String $iv
|
398 |
+
*/
|
399 |
+
function _generate_xor($length, &$iv)
|
400 |
+
{
|
401 |
+
$xor = '';
|
402 |
+
$num_blocks = ($length + 7) >> 3;
|
403 |
+
for ($i = 0; $i < $num_blocks; $i++) {
|
404 |
+
$xor.= $iv;
|
405 |
+
for ($j = 4; $j <= 8; $j+=4) {
|
406 |
+
$temp = substr($iv, -$j, 4);
|
407 |
+
switch ($temp) {
|
408 |
+
case "\xFF\xFF\xFF\xFF":
|
409 |
+
$iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
|
410 |
+
break;
|
411 |
+
case "\x7F\xFF\xFF\xFF":
|
412 |
+
$iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
|
413 |
+
break 2;
|
414 |
+
default:
|
415 |
+
extract(unpack('Ncount', $temp));
|
416 |
+
$iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
|
417 |
+
break 2;
|
418 |
+
}
|
419 |
+
}
|
420 |
+
}
|
421 |
+
|
422 |
+
return $xor;
|
423 |
+
}
|
424 |
+
|
425 |
+
/**
|
426 |
+
* Encrypts a message.
|
427 |
+
*
|
428 |
+
* $plaintext will be padded with up to 8 additional bytes. Other DES implementations may or may not pad in the
|
429 |
+
* same manner. Other common approaches to padding and the reasons why it's necessary are discussed in the following
|
430 |
+
* URL:
|
431 |
+
*
|
432 |
+
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
|
433 |
+
*
|
434 |
+
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
|
435 |
+
* strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
|
436 |
+
* length.
|
437 |
+
*
|
438 |
+
* @see Crypt_DES::decrypt()
|
439 |
+
* @access public
|
440 |
+
* @param String $plaintext
|
441 |
+
*/
|
442 |
+
function encrypt($plaintext)
|
443 |
+
{
|
444 |
+
if ($this->paddable) {
|
445 |
+
$plaintext = $this->_pad($plaintext);
|
446 |
+
}
|
447 |
+
|
448 |
+
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
|
449 |
+
if ($this->enchanged) {
|
450 |
+
if (!isset($this->enmcrypt)) {
|
451 |
+
$this->enmcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
|
452 |
+
}
|
453 |
+
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
|
454 |
+
if ($this->mode != 'ncfb') {
|
455 |
+
$this->enchanged = false;
|
456 |
+
}
|
457 |
+
}
|
458 |
+
|
459 |
+
if ($this->mode != 'ncfb') {
|
460 |
+
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
|
461 |
+
} else {
|
462 |
+
if ($this->enchanged) {
|
463 |
+
$this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
|
464 |
+
mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0");
|
465 |
+
$this->enchanged = false;
|
466 |
+
}
|
467 |
+
|
468 |
+
if (strlen($this->enbuffer)) {
|
469 |
+
$ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer));
|
470 |
+
$this->enbuffer.= $ciphertext;
|
471 |
+
if (strlen($this->enbuffer) == 8) {
|
472 |
+
$this->encryptIV = $this->enbuffer;
|
473 |
+
$this->enbuffer = '';
|
474 |
+
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
|
475 |
+
}
|
476 |
+
$plaintext = substr($plaintext, strlen($ciphertext));
|
477 |
+
} else {
|
478 |
+
$ciphertext = '';
|
479 |
+
}
|
480 |
+
|
481 |
+
$last_pos = strlen($plaintext) & 0xFFFFFFF8;
|
482 |
+
$ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : '';
|
483 |
+
|
484 |
+
if (strlen($plaintext) & 0x7) {
|
485 |
+
if (strlen($ciphertext)) {
|
486 |
+
$this->encryptIV = substr($ciphertext, -8);
|
487 |
+
}
|
488 |
+
$this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV);
|
489 |
+
$this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV;
|
490 |
+
$ciphertext.= $this->enbuffer;
|
491 |
+
}
|
492 |
+
}
|
493 |
+
|
494 |
+
if (!$this->continuousBuffer) {
|
495 |
+
mcrypt_generic_init($this->enmcrypt, $this->keys, $this->encryptIV);
|
496 |
+
}
|
497 |
+
|
498 |
+
return $ciphertext;
|
499 |
+
}
|
500 |
+
|
501 |
+
if (!is_array($this->keys)) {
|
502 |
+
$this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
|
503 |
+
}
|
504 |
+
|
505 |
+
$buffer = &$this->enbuffer;
|
506 |
+
$continuousBuffer = $this->continuousBuffer;
|
507 |
+
$ciphertext = '';
|
508 |
+
switch ($this->mode) {
|
509 |
+
case CRYPT_DES_MODE_ECB:
|
510 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
511 |
+
$ciphertext.= $this->_processBlock(substr($plaintext, $i, 8), CRYPT_DES_ENCRYPT);
|
512 |
+
}
|
513 |
+
break;
|
514 |
+
case CRYPT_DES_MODE_CBC:
|
515 |
+
$xor = $this->encryptIV;
|
516 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
517 |
+
$block = substr($plaintext, $i, 8);
|
518 |
+
$block = $this->_processBlock($block ^ $xor, CRYPT_DES_ENCRYPT);
|
519 |
+
$xor = $block;
|
520 |
+
$ciphertext.= $block;
|
521 |
+
}
|
522 |
+
if ($this->continuousBuffer) {
|
523 |
+
$this->encryptIV = $xor;
|
524 |
+
}
|
525 |
+
break;
|
526 |
+
case CRYPT_DES_MODE_CTR:
|
527 |
+
$xor = $this->encryptIV;
|
528 |
+
if (strlen($buffer)) {
|
529 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
530 |
+
$block = substr($plaintext, $i, 8);
|
531 |
+
$buffer.= $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
|
532 |
+
$key = $this->_string_shift($buffer, 8);
|
533 |
+
$ciphertext.= $block ^ $key;
|
534 |
+
}
|
535 |
+
} else {
|
536 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
537 |
+
$block = substr($plaintext, $i, 8);
|
538 |
+
$key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
|
539 |
+
$ciphertext.= $block ^ $key;
|
540 |
+
}
|
541 |
+
}
|
542 |
+
if ($this->continuousBuffer) {
|
543 |
+
$this->encryptIV = $xor;
|
544 |
+
if ($start = strlen($plaintext) & 7) {
|
545 |
+
$buffer = substr($key, $start) . $buffer;
|
546 |
+
}
|
547 |
+
}
|
548 |
+
break;
|
549 |
+
case CRYPT_DES_MODE_CFB:
|
550 |
+
if (!empty($buffer['xor'])) {
|
551 |
+
$ciphertext = $plaintext ^ $buffer['xor'];
|
552 |
+
$iv = $buffer['encrypted'] . $ciphertext;
|
553 |
+
$start = strlen($ciphertext);
|
554 |
+
$buffer['encrypted'].= $ciphertext;
|
555 |
+
$buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
|
556 |
+
} else {
|
557 |
+
$ciphertext = '';
|
558 |
+
$iv = $this->encryptIV;
|
559 |
+
$start = 0;
|
560 |
+
}
|
561 |
+
|
562 |
+
for ($i = $start; $i < strlen($plaintext); $i+=8) {
|
563 |
+
$block = substr($plaintext, $i, 8);
|
564 |
+
$xor = $this->_processBlock($iv, CRYPT_DES_ENCRYPT);
|
565 |
+
$iv = $block ^ $xor;
|
566 |
+
if ($continuousBuffer && strlen($iv) != 8) {
|
567 |
+
$buffer = array(
|
568 |
+
'encrypted' => $iv,
|
569 |
+
'xor' => substr($xor, strlen($iv))
|
570 |
+
);
|
571 |
+
}
|
572 |
+
$ciphertext.= $iv;
|
573 |
+
}
|
574 |
+
|
575 |
+
if ($this->continuousBuffer) {
|
576 |
+
$this->encryptIV = $iv;
|
577 |
+
}
|
578 |
+
break;
|
579 |
+
case CRYPT_DES_MODE_OFB:
|
580 |
+
$xor = $this->encryptIV;
|
581 |
+
if (strlen($buffer)) {
|
582 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
583 |
+
$xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
584 |
+
$buffer.= $xor;
|
585 |
+
$key = $this->_string_shift($buffer, 8);
|
586 |
+
$ciphertext.= substr($plaintext, $i, 8) ^ $key;
|
587 |
+
}
|
588 |
+
} else {
|
589 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
590 |
+
$xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
591 |
+
$ciphertext.= substr($plaintext, $i, 8) ^ $xor;
|
592 |
+
}
|
593 |
+
$key = $xor;
|
594 |
+
}
|
595 |
+
if ($this->continuousBuffer) {
|
596 |
+
$this->encryptIV = $xor;
|
597 |
+
if ($start = strlen($plaintext) & 7) {
|
598 |
+
$buffer = substr($key, $start) . $buffer;
|
599 |
+
}
|
600 |
+
}
|
601 |
+
}
|
602 |
+
|
603 |
+
return $ciphertext;
|
604 |
+
}
|
605 |
+
|
606 |
+
/**
|
607 |
+
* Decrypts a message.
|
608 |
+
*
|
609 |
+
* If strlen($ciphertext) is not a multiple of 8, null bytes will be added to the end of the string until it is.
|
610 |
+
*
|
611 |
+
* @see Crypt_DES::encrypt()
|
612 |
+
* @access public
|
613 |
+
* @param String $ciphertext
|
614 |
+
*/
|
615 |
+
function decrypt($ciphertext)
|
616 |
+
{
|
617 |
+
if ($this->paddable) {
|
618 |
+
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
|
619 |
+
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
620 |
+
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
|
621 |
+
}
|
622 |
+
|
623 |
+
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
|
624 |
+
if ($this->dechanged) {
|
625 |
+
if (!isset($this->demcrypt)) {
|
626 |
+
$this->demcrypt = mcrypt_module_open(MCRYPT_DES, '', $this->mode, '');
|
627 |
+
}
|
628 |
+
mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
|
629 |
+
if ($this->mode != 'ncfb') {
|
630 |
+
$this->dechanged = false;
|
631 |
+
}
|
632 |
+
}
|
633 |
+
|
634 |
+
if ($this->mode != 'ncfb') {
|
635 |
+
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
|
636 |
+
} else {
|
637 |
+
if ($this->dechanged) {
|
638 |
+
$this->ecb = mcrypt_module_open(MCRYPT_DES, '', MCRYPT_MODE_ECB, '');
|
639 |
+
mcrypt_generic_init($this->ecb, $this->keys, "\0\0\0\0\0\0\0\0");
|
640 |
+
$this->dechanged = false;
|
641 |
+
}
|
642 |
+
|
643 |
+
if (strlen($this->debuffer)) {
|
644 |
+
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer));
|
645 |
+
|
646 |
+
$this->debuffer.= substr($ciphertext, 0, strlen($plaintext));
|
647 |
+
if (strlen($this->debuffer) == 8) {
|
648 |
+
$this->decryptIV = $this->debuffer;
|
649 |
+
$this->debuffer = '';
|
650 |
+
mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
|
651 |
+
}
|
652 |
+
$ciphertext = substr($ciphertext, strlen($plaintext));
|
653 |
+
} else {
|
654 |
+
$plaintext = '';
|
655 |
+
}
|
656 |
+
|
657 |
+
$last_pos = strlen($ciphertext) & 0xFFFFFFF8;
|
658 |
+
$plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : '';
|
659 |
+
|
660 |
+
if (strlen($ciphertext) & 0x7) {
|
661 |
+
if (strlen($plaintext)) {
|
662 |
+
$this->decryptIV = substr($ciphertext, $last_pos - 8, 8);
|
663 |
+
}
|
664 |
+
$this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV);
|
665 |
+
$this->debuffer = substr($ciphertext, $last_pos);
|
666 |
+
$plaintext.= $this->debuffer ^ $this->decryptIV;
|
667 |
+
}
|
668 |
+
|
669 |
+
return $plaintext;
|
670 |
+
}
|
671 |
+
|
672 |
+
if (!$this->continuousBuffer) {
|
673 |
+
mcrypt_generic_init($this->demcrypt, $this->keys, $this->decryptIV);
|
674 |
+
}
|
675 |
+
|
676 |
+
return $this->mode != 'ctr' ? $this->_unpad($plaintext) : $plaintext;
|
677 |
+
}
|
678 |
+
|
679 |
+
if (!is_array($this->keys)) {
|
680 |
+
$this->keys = $this->_prepareKey("\0\0\0\0\0\0\0\0");
|
681 |
+
}
|
682 |
+
|
683 |
+
$buffer = &$this->debuffer;
|
684 |
+
$continuousBuffer = $this->continuousBuffer;
|
685 |
+
$plaintext = '';
|
686 |
+
switch ($this->mode) {
|
687 |
+
case CRYPT_DES_MODE_ECB:
|
688 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
689 |
+
$plaintext.= $this->_processBlock(substr($ciphertext, $i, 8), CRYPT_DES_DECRYPT);
|
690 |
+
}
|
691 |
+
break;
|
692 |
+
case CRYPT_DES_MODE_CBC:
|
693 |
+
$xor = $this->decryptIV;
|
694 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
695 |
+
$block = substr($ciphertext, $i, 8);
|
696 |
+
$plaintext.= $this->_processBlock($block, CRYPT_DES_DECRYPT) ^ $xor;
|
697 |
+
$xor = $block;
|
698 |
+
}
|
699 |
+
if ($this->continuousBuffer) {
|
700 |
+
$this->decryptIV = $xor;
|
701 |
+
}
|
702 |
+
break;
|
703 |
+
case CRYPT_DES_MODE_CTR:
|
704 |
+
$xor = $this->decryptIV;
|
705 |
+
if (strlen($buffer)) {
|
706 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
707 |
+
$block = substr($ciphertext, $i, 8);
|
708 |
+
$buffer.= $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
|
709 |
+
$key = $this->_string_shift($buffer, 8);
|
710 |
+
$plaintext.= $block ^ $key;
|
711 |
+
}
|
712 |
+
} else {
|
713 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
714 |
+
$block = substr($ciphertext, $i, 8);
|
715 |
+
$key = $this->_processBlock($this->_generate_xor(8, $xor), CRYPT_DES_ENCRYPT);
|
716 |
+
$plaintext.= $block ^ $key;
|
717 |
+
}
|
718 |
+
}
|
719 |
+
if ($this->continuousBuffer) {
|
720 |
+
$this->decryptIV = $xor;
|
721 |
+
if ($start = strlen($ciphertext) % 8) {
|
722 |
+
$buffer = substr($key, $start) . $buffer;
|
723 |
+
}
|
724 |
+
}
|
725 |
+
break;
|
726 |
+
case CRYPT_DES_MODE_CFB:
|
727 |
+
if (!empty($buffer['ciphertext'])) {
|
728 |
+
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
|
729 |
+
$buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
|
730 |
+
if (strlen($buffer['ciphertext']) == 8) {
|
731 |
+
$xor = $this->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT);
|
732 |
+
$buffer['ciphertext'] = '';
|
733 |
+
}
|
734 |
+
$start = strlen($plaintext);
|
735 |
+
$block = $this->decryptIV;
|
736 |
+
} else {
|
737 |
+
$plaintext = '';
|
738 |
+
$xor = $this->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
|
739 |
+
$start = 0;
|
740 |
+
}
|
741 |
+
|
742 |
+
for ($i = $start; $i < strlen($ciphertext); $i+=8) {
|
743 |
+
$block = substr($ciphertext, $i, 8);
|
744 |
+
$plaintext.= $block ^ $xor;
|
745 |
+
if ($continuousBuffer && strlen($block) != 8) {
|
746 |
+
$buffer['ciphertext'].= $block;
|
747 |
+
$block = $xor;
|
748 |
+
} else if (strlen($block) == 8) {
|
749 |
+
$xor = $this->_processBlock($block, CRYPT_DES_ENCRYPT);
|
750 |
+
}
|
751 |
+
}
|
752 |
+
if ($this->continuousBuffer) {
|
753 |
+
$this->decryptIV = $block;
|
754 |
+
}
|
755 |
+
break;
|
756 |
+
case CRYPT_DES_MODE_OFB:
|
757 |
+
$xor = $this->decryptIV;
|
758 |
+
if (strlen($buffer)) {
|
759 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
760 |
+
$xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
761 |
+
$buffer.= $xor;
|
762 |
+
$key = $this->_string_shift($buffer, 8);
|
763 |
+
$plaintext.= substr($ciphertext, $i, 8) ^ $key;
|
764 |
+
}
|
765 |
+
} else {
|
766 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
767 |
+
$xor = $this->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
768 |
+
$plaintext.= substr($ciphertext, $i, 8) ^ $xor;
|
769 |
+
}
|
770 |
+
$key = $xor;
|
771 |
+
}
|
772 |
+
if ($this->continuousBuffer) {
|
773 |
+
$this->decryptIV = $xor;
|
774 |
+
if ($start = strlen($ciphertext) % 8) {
|
775 |
+
$buffer = substr($key, $start) . $buffer;
|
776 |
+
}
|
777 |
+
}
|
778 |
+
}
|
779 |
+
|
780 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
781 |
+
}
|
782 |
+
|
783 |
+
/**
|
784 |
+
* Treat consecutive "packets" as if they are a continuous buffer.
|
785 |
+
*
|
786 |
+
* Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
|
787 |
+
* will yield different outputs:
|
788 |
+
*
|
789 |
+
* <code>
|
790 |
+
* echo $des->encrypt(substr($plaintext, 0, 8));
|
791 |
+
* echo $des->encrypt(substr($plaintext, 8, 8));
|
792 |
+
* </code>
|
793 |
+
* <code>
|
794 |
+
* echo $des->encrypt($plaintext);
|
795 |
+
* </code>
|
796 |
+
*
|
797 |
+
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
|
798 |
+
* another, as demonstrated with the following:
|
799 |
+
*
|
800 |
+
* <code>
|
801 |
+
* $des->encrypt(substr($plaintext, 0, 8));
|
802 |
+
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
803 |
+
* </code>
|
804 |
+
* <code>
|
805 |
+
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
806 |
+
* </code>
|
807 |
+
*
|
808 |
+
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
|
809 |
+
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
|
810 |
+
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
|
811 |
+
*
|
812 |
+
* Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
|
813 |
+
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
|
814 |
+
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
|
815 |
+
* however, they are also less intuitive and more likely to cause you problems.
|
816 |
+
*
|
817 |
+
* @see Crypt_DES::disableContinuousBuffer()
|
818 |
+
* @access public
|
819 |
+
*/
|
820 |
+
function enableContinuousBuffer()
|
821 |
+
{
|
822 |
+
$this->continuousBuffer = true;
|
823 |
+
}
|
824 |
+
|
825 |
+
/**
|
826 |
+
* Treat consecutive packets as if they are a discontinuous buffer.
|
827 |
+
*
|
828 |
+
* The default behavior.
|
829 |
+
*
|
830 |
+
* @see Crypt_DES::enableContinuousBuffer()
|
831 |
+
* @access public
|
832 |
+
*/
|
833 |
+
function disableContinuousBuffer()
|
834 |
+
{
|
835 |
+
$this->continuousBuffer = false;
|
836 |
+
$this->encryptIV = $this->iv;
|
837 |
+
$this->decryptIV = $this->iv;
|
838 |
+
}
|
839 |
+
|
840 |
+
/**
|
841 |
+
* Pad "packets".
|
842 |
+
*
|
843 |
+
* DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not
|
844 |
+
* a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight.
|
845 |
+
*
|
846 |
+
* Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
|
847 |
+
* where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
|
848 |
+
* away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
|
849 |
+
* transmitted separately)
|
850 |
+
*
|
851 |
+
* @see Crypt_DES::disablePadding()
|
852 |
+
* @access public
|
853 |
+
*/
|
854 |
+
function enablePadding()
|
855 |
+
{
|
856 |
+
$this->padding = true;
|
857 |
+
}
|
858 |
+
|
859 |
+
/**
|
860 |
+
* Do not pad packets.
|
861 |
+
*
|
862 |
+
* @see Crypt_DES::enablePadding()
|
863 |
+
* @access public
|
864 |
+
*/
|
865 |
+
function disablePadding()
|
866 |
+
{
|
867 |
+
$this->padding = false;
|
868 |
+
}
|
869 |
+
|
870 |
+
/**
|
871 |
+
* Pads a string
|
872 |
+
*
|
873 |
+
* Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
|
874 |
+
* 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7)
|
875 |
+
*
|
876 |
+
* If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
|
877 |
+
* and padding will, hence forth, be enabled.
|
878 |
+
*
|
879 |
+
* @see Crypt_DES::_unpad()
|
880 |
+
* @access private
|
881 |
+
*/
|
882 |
+
function _pad($text)
|
883 |
+
{
|
884 |
+
$length = strlen($text);
|
885 |
+
|
886 |
+
if (!$this->padding) {
|
887 |
+
if (($length & 7) == 0) {
|
888 |
+
return $text;
|
889 |
+
} else {
|
890 |
+
user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE);
|
891 |
+
$this->padding = true;
|
892 |
+
}
|
893 |
+
}
|
894 |
+
|
895 |
+
$pad = 8 - ($length & 7);
|
896 |
+
return str_pad($text, $length + $pad, chr($pad));
|
897 |
+
}
|
898 |
+
|
899 |
+
/**
|
900 |
+
* Unpads a string
|
901 |
+
*
|
902 |
+
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
|
903 |
+
* and false will be returned.
|
904 |
+
*
|
905 |
+
* @see Crypt_DES::_pad()
|
906 |
+
* @access private
|
907 |
+
*/
|
908 |
+
function _unpad($text)
|
909 |
+
{
|
910 |
+
if (!$this->padding) {
|
911 |
+
return $text;
|
912 |
+
}
|
913 |
+
|
914 |
+
$length = ord($text[strlen($text) - 1]);
|
915 |
+
|
916 |
+
if (!$length || $length > 8) {
|
917 |
+
return false;
|
918 |
+
}
|
919 |
+
|
920 |
+
return substr($text, 0, -$length);
|
921 |
+
}
|
922 |
+
|
923 |
+
/**
|
924 |
+
* Encrypts or decrypts a 64-bit block
|
925 |
+
*
|
926 |
+
* $mode should be either CRYPT_DES_ENCRYPT or CRYPT_DES_DECRYPT. See
|
927 |
+
* {@link http://en.wikipedia.org/wiki/Image:Feistel.png Feistel.png} to get a general
|
928 |
+
* idea of what this function does.
|
929 |
+
*
|
930 |
+
* @access private
|
931 |
+
* @param String $block
|
932 |
+
* @param Integer $mode
|
933 |
+
* @return String
|
934 |
+
*/
|
935 |
+
function _processBlock($block, $mode)
|
936 |
+
{
|
937 |
+
// s-boxes. in the official DES docs, they're described as being matrices that
|
938 |
+
// one accesses by using the first and last bits to determine the row and the
|
939 |
+
// middle four bits to determine the column. in this implementation, they've
|
940 |
+
// been converted to vectors
|
941 |
+
static $sbox = array(
|
942 |
+
array(
|
943 |
+
14, 0, 4, 15, 13, 7, 1, 4, 2, 14, 15, 2, 11, 13, 8, 1,
|
944 |
+
3, 10 ,10, 6, 6, 12, 12, 11, 5, 9, 9, 5, 0, 3, 7, 8,
|
945 |
+
4, 15, 1, 12, 14, 8, 8, 2, 13, 4, 6, 9, 2, 1, 11, 7,
|
946 |
+
15, 5, 12, 11, 9, 3, 7, 14, 3, 10, 10, 0, 5, 6, 0, 13
|
947 |
+
),
|
948 |
+
array(
|
949 |
+
15, 3, 1, 13, 8, 4, 14, 7, 6, 15, 11, 2, 3, 8, 4, 14,
|
950 |
+
9, 12, 7, 0, 2, 1, 13, 10, 12, 6, 0, 9, 5, 11, 10, 5,
|
951 |
+
0, 13, 14, 8, 7, 10, 11, 1, 10, 3, 4, 15, 13, 4, 1, 2,
|
952 |
+
5, 11, 8, 6, 12, 7, 6, 12, 9, 0, 3, 5, 2, 14, 15, 9
|
953 |
+
),
|
954 |
+
array(
|
955 |
+
10, 13, 0, 7, 9, 0, 14, 9, 6, 3, 3, 4, 15, 6, 5, 10,
|
956 |
+
1, 2, 13, 8, 12, 5, 7, 14, 11, 12, 4, 11, 2, 15, 8, 1,
|
957 |
+
13, 1, 6, 10, 4, 13, 9, 0, 8, 6, 15, 9, 3, 8, 0, 7,
|
958 |
+
11, 4, 1, 15, 2, 14, 12, 3, 5, 11, 10, 5, 14, 2, 7, 12
|
959 |
+
),
|
960 |
+
array(
|
961 |
+
7, 13, 13, 8, 14, 11, 3, 5, 0, 6, 6, 15, 9, 0, 10, 3,
|
962 |
+
1, 4, 2, 7, 8, 2, 5, 12, 11, 1, 12, 10, 4, 14, 15, 9,
|
963 |
+
10, 3, 6, 15, 9, 0, 0, 6, 12, 10, 11, 1, 7, 13, 13, 8,
|
964 |
+
15, 9, 1, 4, 3, 5, 14, 11, 5, 12, 2, 7, 8, 2, 4, 14
|
965 |
+
),
|
966 |
+
array(
|
967 |
+
2, 14, 12, 11, 4, 2, 1, 12, 7, 4, 10, 7, 11, 13, 6, 1,
|
968 |
+
8, 5, 5, 0, 3, 15, 15, 10, 13, 3, 0, 9, 14, 8, 9, 6,
|
969 |
+
4, 11, 2, 8, 1, 12, 11, 7, 10, 1, 13, 14, 7, 2, 8, 13,
|
970 |
+
15, 6, 9, 15, 12, 0, 5, 9, 6, 10, 3, 4, 0, 5, 14, 3
|
971 |
+
),
|
972 |
+
array(
|
973 |
+
12, 10, 1, 15, 10, 4, 15, 2, 9, 7, 2, 12, 6, 9, 8, 5,
|
974 |
+
0, 6, 13, 1, 3, 13, 4, 14, 14, 0, 7, 11, 5, 3, 11, 8,
|
975 |
+
9, 4, 14, 3, 15, 2, 5, 12, 2, 9, 8, 5, 12, 15, 3, 10,
|
976 |
+
7, 11, 0, 14, 4, 1, 10, 7, 1, 6, 13, 0, 11, 8, 6, 13
|
977 |
+
),
|
978 |
+
array(
|
979 |
+
4, 13, 11, 0, 2, 11, 14, 7, 15, 4, 0, 9, 8, 1, 13, 10,
|
980 |
+
3, 14, 12, 3, 9, 5, 7, 12, 5, 2, 10, 15, 6, 8, 1, 6,
|
981 |
+
1, 6, 4, 11, 11, 13, 13, 8, 12, 1, 3, 4, 7, 10, 14, 7,
|
982 |
+
10, 9, 15, 5, 6, 0, 8, 15, 0, 14, 5, 2, 9, 3, 2, 12
|
983 |
+
),
|
984 |
+
array(
|
985 |
+
13, 1, 2, 15, 8, 13, 4, 8, 6, 10, 15, 3, 11, 7, 1, 4,
|
986 |
+
10, 12, 9, 5, 3, 6, 14, 11, 5, 0, 0, 14, 12, 9, 7, 2,
|
987 |
+
7, 2, 11, 1, 4, 14, 1, 7, 9, 4, 12, 10, 14, 8, 2, 13,
|
988 |
+
0, 15, 6, 12, 10, 9, 13, 0, 15, 3, 3, 5, 5, 6, 8, 11
|
989 |
+
)
|
990 |
+
);
|
991 |
+
|
992 |
+
$keys = $this->keys;
|
993 |
+
|
994 |
+
$temp = unpack('Na/Nb', $block);
|
995 |
+
$block = array($temp['a'], $temp['b']);
|
996 |
+
|
997 |
+
// because php does arithmetic right shifts, if the most significant bits are set, right
|
998 |
+
// shifting those into the correct position will add 1's - not 0's. this will intefere
|
999 |
+
// with the | operation unless a second & is done. so we isolate these bits and left shift
|
1000 |
+
// them into place. we then & each block with 0x7FFFFFFF to prevennt 1's from being added
|
1001 |
+
// for any other shifts.
|
1002 |
+
$msb = array(
|
1003 |
+
($block[0] >> 31) & 1,
|
1004 |
+
($block[1] >> 31) & 1
|
1005 |
+
);
|
1006 |
+
$block[0] &= 0x7FFFFFFF;
|
1007 |
+
$block[1] &= 0x7FFFFFFF;
|
1008 |
+
|
1009 |
+
// we isolate the appropriate bit in the appropriate integer and shift as appropriate. in
|
1010 |
+
// some cases, there are going to be multiple bits in the same integer that need to be shifted
|
1011 |
+
// in the same way. we combine those into one shift operation.
|
1012 |
+
$block = array(
|
1013 |
+
(($block[1] & 0x00000040) << 25) | (($block[1] & 0x00004000) << 16) |
|
1014 |
+
(($block[1] & 0x00400001) << 7) | (($block[1] & 0x40000100) >> 2) |
|
1015 |
+
(($block[0] & 0x00000040) << 21) | (($block[0] & 0x00004000) << 12) |
|
1016 |
+
(($block[0] & 0x00400001) << 3) | (($block[0] & 0x40000100) >> 6) |
|
1017 |
+
(($block[1] & 0x00000010) << 19) | (($block[1] & 0x00001000) << 10) |
|
1018 |
+
(($block[1] & 0x00100000) << 1) | (($block[1] & 0x10000000) >> 8) |
|
1019 |
+
(($block[0] & 0x00000010) << 15) | (($block[0] & 0x00001000) << 6) |
|
1020 |
+
(($block[0] & 0x00100000) >> 3) | (($block[0] & 0x10000000) >> 12) |
|
1021 |
+
(($block[1] & 0x00000004) << 13) | (($block[1] & 0x00000400) << 4) |
|
1022 |
+
(($block[1] & 0x00040000) >> 5) | (($block[1] & 0x04000000) >> 14) |
|
1023 |
+
(($block[0] & 0x00000004) << 9) | ( $block[0] & 0x00000400 ) |
|
1024 |
+
(($block[0] & 0x00040000) >> 9) | (($block[0] & 0x04000000) >> 18) |
|
1025 |
+
(($block[1] & 0x00010000) >> 11) | (($block[1] & 0x01000000) >> 20) |
|
1026 |
+
(($block[0] & 0x00010000) >> 15) | (($block[0] & 0x01000000) >> 24)
|
1027 |
+
,
|
1028 |
+
(($block[1] & 0x00000080) << 24) | (($block[1] & 0x00008000) << 15) |
|
1029 |
+
(($block[1] & 0x00800002) << 6) | (($block[0] & 0x00000080) << 20) |
|
1030 |
+
(($block[0] & 0x00008000) << 11) | (($block[0] & 0x00800002) << 2) |
|
1031 |
+
(($block[1] & 0x00000020) << 18) | (($block[1] & 0x00002000) << 9) |
|
1032 |
+
( $block[1] & 0x00200000 ) | (($block[1] & 0x20000000) >> 9) |
|
1033 |
+
(($block[0] & 0x00000020) << 14) | (($block[0] & 0x00002000) << 5) |
|
1034 |
+
(($block[0] & 0x00200000) >> 4) | (($block[0] & 0x20000000) >> 13) |
|
1035 |
+
(($block[1] & 0x00000008) << 12) | (($block[1] & 0x00000800) << 3) |
|
1036 |
+
(($block[1] & 0x00080000) >> 6) | (($block[1] & 0x08000000) >> 15) |
|
1037 |
+
(($block[0] & 0x00000008) << 8) | (($block[0] & 0x00000800) >> 1) |
|
1038 |
+
(($block[0] & 0x00080000) >> 10) | (($block[0] & 0x08000000) >> 19) |
|
1039 |
+
(($block[1] & 0x00000200) >> 3) | (($block[0] & 0x00000200) >> 7) |
|
1040 |
+
(($block[1] & 0x00020000) >> 12) | (($block[1] & 0x02000000) >> 21) |
|
1041 |
+
(($block[0] & 0x00020000) >> 16) | (($block[0] & 0x02000000) >> 25) |
|
1042 |
+
($msb[1] << 28) | ($msb[0] << 24)
|
1043 |
+
);
|
1044 |
+
|
1045 |
+
for ($i = 0; $i < 16; $i++) {
|
1046 |
+
// start of "the Feistel (F) function" - see the following URL:
|
1047 |
+
// http://en.wikipedia.org/wiki/Image:Data_Encryption_Standard_InfoBox_Diagram.png
|
1048 |
+
$temp = (($sbox[0][((($block[1] >> 27) & 0x1F) | (($block[1] & 1) << 5)) ^ $keys[$mode][$i][0]]) << 28)
|
1049 |
+
| (($sbox[1][(($block[1] & 0x1F800000) >> 23) ^ $keys[$mode][$i][1]]) << 24)
|
1050 |
+
| (($sbox[2][(($block[1] & 0x01F80000) >> 19) ^ $keys[$mode][$i][2]]) << 20)
|
1051 |
+
| (($sbox[3][(($block[1] & 0x001F8000) >> 15) ^ $keys[$mode][$i][3]]) << 16)
|
1052 |
+
| (($sbox[4][(($block[1] & 0x0001F800) >> 11) ^ $keys[$mode][$i][4]]) << 12)
|
1053 |
+
| (($sbox[5][(($block[1] & 0x00001F80) >> 7) ^ $keys[$mode][$i][5]]) << 8)
|
1054 |
+
| (($sbox[6][(($block[1] & 0x000001F8) >> 3) ^ $keys[$mode][$i][6]]) << 4)
|
1055 |
+
| ( $sbox[7][((($block[1] & 0x1F) << 1) | (($block[1] >> 31) & 1)) ^ $keys[$mode][$i][7]]);
|
1056 |
+
|
1057 |
+
$msb = ($temp >> 31) & 1;
|
1058 |
+
$temp &= 0x7FFFFFFF;
|
1059 |
+
$newBlock = (($temp & 0x00010000) << 15) | (($temp & 0x02020120) << 5)
|
1060 |
+
| (($temp & 0x00001800) << 17) | (($temp & 0x01000000) >> 10)
|
1061 |
+
| (($temp & 0x00000008) << 24) | (($temp & 0x00100000) << 6)
|
1062 |
+
| (($temp & 0x00000010) << 21) | (($temp & 0x00008000) << 9)
|
1063 |
+
| (($temp & 0x00000200) << 12) | (($temp & 0x10000000) >> 27)
|
1064 |
+
| (($temp & 0x00000040) << 14) | (($temp & 0x08000000) >> 8)
|
1065 |
+
| (($temp & 0x00004000) << 4) | (($temp & 0x00000002) << 16)
|
1066 |
+
| (($temp & 0x00442000) >> 6) | (($temp & 0x40800000) >> 15)
|
1067 |
+
| (($temp & 0x00000001) << 11) | (($temp & 0x20000000) >> 20)
|
1068 |
+
| (($temp & 0x00080000) >> 13) | (($temp & 0x00000004) << 3)
|
1069 |
+
| (($temp & 0x04000000) >> 22) | (($temp & 0x00000480) >> 7)
|
1070 |
+
| (($temp & 0x00200000) >> 19) | ($msb << 23);
|
1071 |
+
// end of "the Feistel (F) function" - $newBlock is F's output
|
1072 |
+
|
1073 |
+
$temp = $block[1];
|
1074 |
+
$block[1] = $block[0] ^ $newBlock;
|
1075 |
+
$block[0] = $temp;
|
1076 |
+
}
|
1077 |
+
|
1078 |
+
$msb = array(
|
1079 |
+
($block[0] >> 31) & 1,
|
1080 |
+
($block[1] >> 31) & 1
|
1081 |
+
);
|
1082 |
+
$block[0] &= 0x7FFFFFFF;
|
1083 |
+
$block[1] &= 0x7FFFFFFF;
|
1084 |
+
|
1085 |
+
$block = array(
|
1086 |
+
(($block[0] & 0x01000004) << 7) | (($block[1] & 0x01000004) << 6) |
|
1087 |
+
(($block[0] & 0x00010000) << 13) | (($block[1] & 0x00010000) << 12) |
|
1088 |
+
(($block[0] & 0x00000100) << 19) | (($block[1] & 0x00000100) << 18) |
|
1089 |
+
(($block[0] & 0x00000001) << 25) | (($block[1] & 0x00000001) << 24) |
|
1090 |
+
(($block[0] & 0x02000008) >> 2) | (($block[1] & 0x02000008) >> 3) |
|
1091 |
+
(($block[0] & 0x00020000) << 4) | (($block[1] & 0x00020000) << 3) |
|
1092 |
+
(($block[0] & 0x00000200) << 10) | (($block[1] & 0x00000200) << 9) |
|
1093 |
+
(($block[0] & 0x00000002) << 16) | (($block[1] & 0x00000002) << 15) |
|
1094 |
+
(($block[0] & 0x04000000) >> 11) | (($block[1] & 0x04000000) >> 12) |
|
1095 |
+
(($block[0] & 0x00040000) >> 5) | (($block[1] & 0x00040000) >> 6) |
|
1096 |
+
(($block[0] & 0x00000400) << 1) | ( $block[1] & 0x00000400 ) |
|
1097 |
+
(($block[0] & 0x08000000) >> 20) | (($block[1] & 0x08000000) >> 21) |
|
1098 |
+
(($block[0] & 0x00080000) >> 14) | (($block[1] & 0x00080000) >> 15) |
|
1099 |
+
(($block[0] & 0x00000800) >> 8) | (($block[1] & 0x00000800) >> 9)
|
1100 |
+
,
|
1101 |
+
(($block[0] & 0x10000040) << 3) | (($block[1] & 0x10000040) << 2) |
|
1102 |
+
(($block[0] & 0x00100000) << 9) | (($block[1] & 0x00100000) << 8) |
|
1103 |
+
(($block[0] & 0x00001000) << 15) | (($block[1] & 0x00001000) << 14) |
|
1104 |
+
(($block[0] & 0x00000010) << 21) | (($block[1] & 0x00000010) << 20) |
|
1105 |
+
(($block[0] & 0x20000080) >> 6) | (($block[1] & 0x20000080) >> 7) |
|
1106 |
+
( $block[0] & 0x00200000 ) | (($block[1] & 0x00200000) >> 1) |
|
1107 |
+
(($block[0] & 0x00002000) << 6) | (($block[1] & 0x00002000) << 5) |
|
1108 |
+
(($block[0] & 0x00000020) << 12) | (($block[1] & 0x00000020) << 11) |
|
1109 |
+
(($block[0] & 0x40000000) >> 15) | (($block[1] & 0x40000000) >> 16) |
|
1110 |
+
(($block[0] & 0x00400000) >> 9) | (($block[1] & 0x00400000) >> 10) |
|
1111 |
+
(($block[0] & 0x00004000) >> 3) | (($block[1] & 0x00004000) >> 4) |
|
1112 |
+
(($block[0] & 0x00800000) >> 18) | (($block[1] & 0x00800000) >> 19) |
|
1113 |
+
(($block[0] & 0x00008000) >> 12) | (($block[1] & 0x00008000) >> 13) |
|
1114 |
+
($msb[0] << 7) | ($msb[1] << 6)
|
1115 |
+
);
|
1116 |
+
|
1117 |
+
return pack('NN', $block[0], $block[1]);
|
1118 |
+
}
|
1119 |
+
|
1120 |
+
/**
|
1121 |
+
* Creates the key schedule.
|
1122 |
+
*
|
1123 |
+
* @access private
|
1124 |
+
* @param String $key
|
1125 |
+
* @return Array
|
1126 |
+
*/
|
1127 |
+
function _prepareKey($key)
|
1128 |
+
{
|
1129 |
+
static $shifts = array( // number of key bits shifted per round
|
1130 |
+
1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1
|
1131 |
+
);
|
1132 |
+
|
1133 |
+
// pad the key and remove extra characters as appropriate.
|
1134 |
+
$key = str_pad(substr($key, 0, 8), 8, chr(0));
|
1135 |
+
|
1136 |
+
$temp = unpack('Na/Nb', $key);
|
1137 |
+
$key = array($temp['a'], $temp['b']);
|
1138 |
+
$msb = array(
|
1139 |
+
($key[0] >> 31) & 1,
|
1140 |
+
($key[1] >> 31) & 1
|
1141 |
+
);
|
1142 |
+
$key[0] &= 0x7FFFFFFF;
|
1143 |
+
$key[1] &= 0x7FFFFFFF;
|
1144 |
+
|
1145 |
+
$key = array(
|
1146 |
+
(($key[1] & 0x00000002) << 26) | (($key[1] & 0x00000204) << 17) |
|
1147 |
+
(($key[1] & 0x00020408) << 8) | (($key[1] & 0x02040800) >> 1) |
|
1148 |
+
(($key[0] & 0x00000002) << 22) | (($key[0] & 0x00000204) << 13) |
|
1149 |
+
(($key[0] & 0x00020408) << 4) | (($key[0] & 0x02040800) >> 5) |
|
1150 |
+
(($key[1] & 0x04080000) >> 10) | (($key[0] & 0x04080000) >> 14) |
|
1151 |
+
(($key[1] & 0x08000000) >> 19) | (($key[0] & 0x08000000) >> 23) |
|
1152 |
+
(($key[0] & 0x00000010) >> 1) | (($key[0] & 0x00001000) >> 10) |
|
1153 |
+
(($key[0] & 0x00100000) >> 19) | (($key[0] & 0x10000000) >> 28)
|
1154 |
+
,
|
1155 |
+
(($key[1] & 0x00000080) << 20) | (($key[1] & 0x00008000) << 11) |
|
1156 |
+
(($key[1] & 0x00800000) << 2) | (($key[0] & 0x00000080) << 16) |
|
1157 |
+
(($key[0] & 0x00008000) << 7) | (($key[0] & 0x00800000) >> 2) |
|
1158 |
+
(($key[1] & 0x00000040) << 13) | (($key[1] & 0x00004000) << 4) |
|
1159 |
+
(($key[1] & 0x00400000) >> 5) | (($key[1] & 0x40000000) >> 14) |
|
1160 |
+
(($key[0] & 0x00000040) << 9) | ( $key[0] & 0x00004000 ) |
|
1161 |
+
(($key[0] & 0x00400000) >> 9) | (($key[0] & 0x40000000) >> 18) |
|
1162 |
+
(($key[1] & 0x00000020) << 6) | (($key[1] & 0x00002000) >> 3) |
|
1163 |
+
(($key[1] & 0x00200000) >> 12) | (($key[1] & 0x20000000) >> 21) |
|
1164 |
+
(($key[0] & 0x00000020) << 2) | (($key[0] & 0x00002000) >> 7) |
|
1165 |
+
(($key[0] & 0x00200000) >> 16) | (($key[0] & 0x20000000) >> 25) |
|
1166 |
+
(($key[1] & 0x00000010) >> 1) | (($key[1] & 0x00001000) >> 10) |
|
1167 |
+
(($key[1] & 0x00100000) >> 19) | (($key[1] & 0x10000000) >> 28) |
|
1168 |
+
($msb[1] << 24) | ($msb[0] << 20)
|
1169 |
+
);
|
1170 |
+
|
1171 |
+
$keys = array();
|
1172 |
+
for ($i = 0; $i < 16; $i++) {
|
1173 |
+
$key[0] <<= $shifts[$i];
|
1174 |
+
$temp = ($key[0] & 0xF0000000) >> 28;
|
1175 |
+
$key[0] = ($key[0] | $temp) & 0x0FFFFFFF;
|
1176 |
+
|
1177 |
+
$key[1] <<= $shifts[$i];
|
1178 |
+
$temp = ($key[1] & 0xF0000000) >> 28;
|
1179 |
+
$key[1] = ($key[1] | $temp) & 0x0FFFFFFF;
|
1180 |
+
|
1181 |
+
$temp = array(
|
1182 |
+
(($key[1] & 0x00004000) >> 9) | (($key[1] & 0x00000800) >> 7) |
|
1183 |
+
(($key[1] & 0x00020000) >> 14) | (($key[1] & 0x00000010) >> 2) |
|
1184 |
+
(($key[1] & 0x08000000) >> 26) | (($key[1] & 0x00800000) >> 23)
|
1185 |
+
,
|
1186 |
+
(($key[1] & 0x02400000) >> 20) | (($key[1] & 0x00000001) << 4) |
|
1187 |
+
(($key[1] & 0x00002000) >> 10) | (($key[1] & 0x00040000) >> 18) |
|
1188 |
+
(($key[1] & 0x00000080) >> 6)
|
1189 |
+
,
|
1190 |
+
( $key[1] & 0x00000020 ) | (($key[1] & 0x00000200) >> 5) |
|
1191 |
+
(($key[1] & 0x00010000) >> 13) | (($key[1] & 0x01000000) >> 22) |
|
1192 |
+
(($key[1] & 0x00000004) >> 1) | (($key[1] & 0x00100000) >> 20)
|
1193 |
+
,
|
1194 |
+
(($key[1] & 0x00001000) >> 7) | (($key[1] & 0x00200000) >> 17) |
|
1195 |
+
(($key[1] & 0x00000002) << 2) | (($key[1] & 0x00000100) >> 6) |
|
1196 |
+
(($key[1] & 0x00008000) >> 14) | (($key[1] & 0x04000000) >> 26)
|
1197 |
+
,
|
1198 |
+
(($key[0] & 0x00008000) >> 10) | ( $key[0] & 0x00000010 ) |
|
1199 |
+
(($key[0] & 0x02000000) >> 22) | (($key[0] & 0x00080000) >> 17) |
|
1200 |
+
(($key[0] & 0x00000200) >> 8) | (($key[0] & 0x00000002) >> 1)
|
1201 |
+
,
|
1202 |
+
(($key[0] & 0x04000000) >> 21) | (($key[0] & 0x00010000) >> 12) |
|
1203 |
+
(($key[0] & 0x00000020) >> 2) | (($key[0] & 0x00000800) >> 9) |
|
1204 |
+
(($key[0] & 0x00800000) >> 22) | (($key[0] & 0x00000100) >> 8)
|
1205 |
+
,
|
1206 |
+
(($key[0] & 0x00001000) >> 7) | (($key[0] & 0x00000088) >> 3) |
|
1207 |
+
(($key[0] & 0x00020000) >> 14) | (($key[0] & 0x00000001) << 2) |
|
1208 |
+
(($key[0] & 0x00400000) >> 21)
|
1209 |
+
,
|
1210 |
+
(($key[0] & 0x00000400) >> 5) | (($key[0] & 0x00004000) >> 10) |
|
1211 |
+
(($key[0] & 0x00000040) >> 3) | (($key[0] & 0x00100000) >> 18) |
|
1212 |
+
(($key[0] & 0x08000000) >> 26) | (($key[0] & 0x01000000) >> 24)
|
1213 |
+
);
|
1214 |
+
|
1215 |
+
$keys[] = $temp;
|
1216 |
+
}
|
1217 |
+
|
1218 |
+
$temp = array(
|
1219 |
+
CRYPT_DES_ENCRYPT => $keys,
|
1220 |
+
CRYPT_DES_DECRYPT => array_reverse($keys)
|
1221 |
+
);
|
1222 |
+
|
1223 |
+
return $temp;
|
1224 |
+
}
|
1225 |
+
|
1226 |
+
/**
|
1227 |
+
* String Shift
|
1228 |
+
*
|
1229 |
+
* Inspired by array_shift
|
1230 |
+
*
|
1231 |
+
* @param String $string
|
1232 |
+
* @param optional Integer $index
|
1233 |
+
* @return String
|
1234 |
+
* @access private
|
1235 |
+
*/
|
1236 |
+
function _string_shift(&$string, $index = 1)
|
1237 |
+
{
|
1238 |
+
$substr = substr($string, 0, $index);
|
1239 |
+
$string = substr($string, $index);
|
1240 |
+
return $substr;
|
1241 |
+
}
|
1242 |
+
}
|
1243 |
+
|
1244 |
+
// vim: ts=4:sw=4:et:
|
1245 |
+
// vim6: fdl=1:
|
classes/phpseclib/Crypt/Hash.php
ADDED
@@ -0,0 +1,824 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
|
6 |
+
*
|
7 |
+
* Uses hash() or mhash() if available and an internal implementation, otherwise. Currently supports the following:
|
8 |
+
*
|
9 |
+
* md2, md5, md5-96, sha1, sha1-96, sha256, sha384, and sha512
|
10 |
+
*
|
11 |
+
* If {@link Crypt_Hash::setKey() setKey()} is called, {@link Crypt_Hash::hash() hash()} will return the HMAC as opposed to
|
12 |
+
* the hash. If no valid algorithm is provided, sha1 will be used.
|
13 |
+
*
|
14 |
+
* PHP versions 4 and 5
|
15 |
+
*
|
16 |
+
* {@internal The variable names are the same as those in
|
17 |
+
* {@link http://tools.ietf.org/html/rfc2104#section-2 RFC2104}.}}
|
18 |
+
*
|
19 |
+
* Here's a short example of how to use this library:
|
20 |
+
* <code>
|
21 |
+
* <?php
|
22 |
+
* include('Crypt/Hash.php');
|
23 |
+
*
|
24 |
+
* $hash = new Crypt_Hash('sha1');
|
25 |
+
*
|
26 |
+
* $hash->setKey('abcdefg');
|
27 |
+
*
|
28 |
+
* echo base64_encode($hash->hash('abcdefg'));
|
29 |
+
* ?>
|
30 |
+
* </code>
|
31 |
+
*
|
32 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
33 |
+
* of this software and associated documentation files (the "Software"), to deal
|
34 |
+
* in the Software without restriction, including without limitation the rights
|
35 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
36 |
+
* copies of the Software, and to permit persons to whom the Software is
|
37 |
+
* furnished to do so, subject to the following conditions:
|
38 |
+
*
|
39 |
+
* The above copyright notice and this permission notice shall be included in
|
40 |
+
* all copies or substantial portions of the Software.
|
41 |
+
*
|
42 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
43 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
44 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
45 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
46 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
47 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
48 |
+
* THE SOFTWARE.
|
49 |
+
*
|
50 |
+
* @category Crypt
|
51 |
+
* @package Crypt_Hash
|
52 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
53 |
+
* @copyright MMVII Jim Wigginton
|
54 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
55 |
+
* @version $Id: Hash.php,v 1.6 2009/11/23 23:37:07 terrafrost Exp $
|
56 |
+
* @link http://phpseclib.sourceforge.net
|
57 |
+
*/
|
58 |
+
|
59 |
+
/**#@+
|
60 |
+
* @access private
|
61 |
+
* @see Crypt_Hash::Crypt_Hash()
|
62 |
+
*/
|
63 |
+
/**
|
64 |
+
* Toggles the internal implementation
|
65 |
+
*/
|
66 |
+
define('CRYPT_HASH_MODE_INTERNAL', 1);
|
67 |
+
/**
|
68 |
+
* Toggles the mhash() implementation, which has been deprecated on PHP 5.3.0+.
|
69 |
+
*/
|
70 |
+
define('CRYPT_HASH_MODE_MHASH', 2);
|
71 |
+
/**
|
72 |
+
* Toggles the hash() implementation, which works on PHP 5.1.2+.
|
73 |
+
*/
|
74 |
+
define('CRYPT_HASH_MODE_HASH', 3);
|
75 |
+
/**#@-*/
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Pure-PHP implementations of keyed-hash message authentication codes (HMACs) and various cryptographic hashing functions.
|
79 |
+
*
|
80 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
81 |
+
* @version 0.1.0
|
82 |
+
* @access public
|
83 |
+
* @package Crypt_Hash
|
84 |
+
*/
|
85 |
+
class Crypt_Hash {
|
86 |
+
/**
|
87 |
+
* Byte-length of compression blocks / key (Internal HMAC)
|
88 |
+
*
|
89 |
+
* @see Crypt_Hash::setAlgorithm()
|
90 |
+
* @var Integer
|
91 |
+
* @access private
|
92 |
+
*/
|
93 |
+
var $b;
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Byte-length of hash output (Internal HMAC)
|
97 |
+
*
|
98 |
+
* @see Crypt_Hash::setHash()
|
99 |
+
* @var Integer
|
100 |
+
* @access private
|
101 |
+
*/
|
102 |
+
var $l = false;
|
103 |
+
|
104 |
+
/**
|
105 |
+
* Hash Algorithm
|
106 |
+
*
|
107 |
+
* @see Crypt_Hash::setHash()
|
108 |
+
* @var String
|
109 |
+
* @access private
|
110 |
+
*/
|
111 |
+
var $hash;
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Key
|
115 |
+
*
|
116 |
+
* @see Crypt_Hash::setKey()
|
117 |
+
* @var String
|
118 |
+
* @access private
|
119 |
+
*/
|
120 |
+
var $key = '';
|
121 |
+
|
122 |
+
/**
|
123 |
+
* Outer XOR (Internal HMAC)
|
124 |
+
*
|
125 |
+
* @see Crypt_Hash::setKey()
|
126 |
+
* @var String
|
127 |
+
* @access private
|
128 |
+
*/
|
129 |
+
var $opad;
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Inner XOR (Internal HMAC)
|
133 |
+
*
|
134 |
+
* @see Crypt_Hash::setKey()
|
135 |
+
* @var String
|
136 |
+
* @access private
|
137 |
+
*/
|
138 |
+
var $ipad;
|
139 |
+
|
140 |
+
/**
|
141 |
+
* Default Constructor.
|
142 |
+
*
|
143 |
+
* @param optional String $hash
|
144 |
+
* @return Crypt_Hash
|
145 |
+
* @access public
|
146 |
+
*/
|
147 |
+
function Crypt_Hash($hash = 'sha1')
|
148 |
+
{
|
149 |
+
if ( !defined('CRYPT_HASH_MODE') ) {
|
150 |
+
switch (true) {
|
151 |
+
case extension_loaded('hash'):
|
152 |
+
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_HASH);
|
153 |
+
break;
|
154 |
+
case extension_loaded('mhash'):
|
155 |
+
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_MHASH);
|
156 |
+
break;
|
157 |
+
default:
|
158 |
+
define('CRYPT_HASH_MODE', CRYPT_HASH_MODE_INTERNAL);
|
159 |
+
}
|
160 |
+
}
|
161 |
+
|
162 |
+
$this->setHash($hash);
|
163 |
+
}
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Sets the key for HMACs
|
167 |
+
*
|
168 |
+
* Keys can be of any length.
|
169 |
+
*
|
170 |
+
* @access public
|
171 |
+
* @param String $key
|
172 |
+
*/
|
173 |
+
function setKey($key)
|
174 |
+
{
|
175 |
+
$this->key = $key;
|
176 |
+
}
|
177 |
+
|
178 |
+
/**
|
179 |
+
* Sets the hash function.
|
180 |
+
*
|
181 |
+
* @access public
|
182 |
+
* @param String $hash
|
183 |
+
*/
|
184 |
+
function setHash($hash)
|
185 |
+
{
|
186 |
+
switch ($hash) {
|
187 |
+
case 'md5-96':
|
188 |
+
case 'sha1-96':
|
189 |
+
$this->l = 12; // 96 / 8 = 12
|
190 |
+
break;
|
191 |
+
case 'md2':
|
192 |
+
case 'md5':
|
193 |
+
$this->l = 16;
|
194 |
+
break;
|
195 |
+
case 'sha1':
|
196 |
+
$this->l = 20;
|
197 |
+
break;
|
198 |
+
case 'sha256':
|
199 |
+
$this->l = 32;
|
200 |
+
break;
|
201 |
+
case 'sha384':
|
202 |
+
$this->l = 48;
|
203 |
+
break;
|
204 |
+
case 'sha512':
|
205 |
+
$this->l = 64;
|
206 |
+
}
|
207 |
+
|
208 |
+
switch ($hash) {
|
209 |
+
case 'md2':
|
210 |
+
$mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_HASH && in_array('md2', hash_algos()) ?
|
211 |
+
CRYPT_HASH_MODE_HASH : CRYPT_HASH_MODE_INTERNAL;
|
212 |
+
break;
|
213 |
+
case 'sha384':
|
214 |
+
case 'sha512':
|
215 |
+
$mode = CRYPT_HASH_MODE == CRYPT_HASH_MODE_MHASH ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
|
216 |
+
break;
|
217 |
+
default:
|
218 |
+
$mode = CRYPT_HASH_MODE;
|
219 |
+
}
|
220 |
+
|
221 |
+
switch ( $mode ) {
|
222 |
+
case CRYPT_HASH_MODE_MHASH:
|
223 |
+
switch ($hash) {
|
224 |
+
case 'md5':
|
225 |
+
case 'md5-96':
|
226 |
+
$this->hash = MHASH_MD5;
|
227 |
+
break;
|
228 |
+
case 'sha256':
|
229 |
+
$this->hash = MHASH_SHA256;
|
230 |
+
break;
|
231 |
+
case 'sha1':
|
232 |
+
case 'sha1-96':
|
233 |
+
default:
|
234 |
+
$this->hash = MHASH_SHA1;
|
235 |
+
}
|
236 |
+
return;
|
237 |
+
case CRYPT_HASH_MODE_HASH:
|
238 |
+
switch ($hash) {
|
239 |
+
case 'md5':
|
240 |
+
case 'md5-96':
|
241 |
+
$this->hash = 'md5';
|
242 |
+
return;
|
243 |
+
case 'md2':
|
244 |
+
case 'sha256':
|
245 |
+
case 'sha384':
|
246 |
+
case 'sha512':
|
247 |
+
$this->hash = $hash;
|
248 |
+
return;
|
249 |
+
case 'sha1':
|
250 |
+
case 'sha1-96':
|
251 |
+
default:
|
252 |
+
$this->hash = 'sha1';
|
253 |
+
}
|
254 |
+
return;
|
255 |
+
}
|
256 |
+
|
257 |
+
switch ($hash) {
|
258 |
+
case 'md2':
|
259 |
+
$this->b = 16;
|
260 |
+
$this->hash = array($this, '_md2');
|
261 |
+
break;
|
262 |
+
case 'md5':
|
263 |
+
case 'md5-96':
|
264 |
+
$this->b = 64;
|
265 |
+
$this->hash = array($this, '_md5');
|
266 |
+
break;
|
267 |
+
case 'sha256':
|
268 |
+
$this->b = 64;
|
269 |
+
$this->hash = array($this, '_sha256');
|
270 |
+
break;
|
271 |
+
case 'sha384':
|
272 |
+
case 'sha512':
|
273 |
+
$this->b = 128;
|
274 |
+
$this->hash = array($this, '_sha512');
|
275 |
+
break;
|
276 |
+
case 'sha1':
|
277 |
+
case 'sha1-96':
|
278 |
+
default:
|
279 |
+
$this->b = 64;
|
280 |
+
$this->hash = array($this, '_sha1');
|
281 |
+
}
|
282 |
+
|
283 |
+
$this->ipad = str_repeat(chr(0x36), $this->b);
|
284 |
+
$this->opad = str_repeat(chr(0x5C), $this->b);
|
285 |
+
}
|
286 |
+
|
287 |
+
/**
|
288 |
+
* Compute the HMAC.
|
289 |
+
*
|
290 |
+
* @access public
|
291 |
+
* @param String $text
|
292 |
+
* @return String
|
293 |
+
*/
|
294 |
+
function hash($text)
|
295 |
+
{
|
296 |
+
$mode = is_array($this->hash) ? CRYPT_HASH_MODE_INTERNAL : CRYPT_HASH_MODE;
|
297 |
+
|
298 |
+
if (!empty($this->key)) {
|
299 |
+
switch ( $mode ) {
|
300 |
+
case CRYPT_HASH_MODE_MHASH:
|
301 |
+
$output = mhash($this->hash, $text, $this->key);
|
302 |
+
break;
|
303 |
+
case CRYPT_HASH_MODE_HASH:
|
304 |
+
$output = hash_hmac($this->hash, $text, $this->key, true);
|
305 |
+
break;
|
306 |
+
case CRYPT_HASH_MODE_INTERNAL:
|
307 |
+
/* "Applications that use keys longer than B bytes will first hash the key using H and then use the
|
308 |
+
resultant L byte string as the actual key to HMAC."
|
309 |
+
|
310 |
+
-- http://tools.ietf.org/html/rfc2104#section-2 */
|
311 |
+
$key = strlen($this->key) > $this->b ? call_user_func($this->hash, $this->key) : $this->key;
|
312 |
+
|
313 |
+
$key = str_pad($key, $this->b, chr(0)); // step 1
|
314 |
+
$temp = $this->ipad ^ $key; // step 2
|
315 |
+
$temp .= $text; // step 3
|
316 |
+
$temp = call_user_func($this->hash, $temp); // step 4
|
317 |
+
$output = $this->opad ^ $key; // step 5
|
318 |
+
$output.= $temp; // step 6
|
319 |
+
$output = call_user_func($this->hash, $output); // step 7
|
320 |
+
}
|
321 |
+
} else {
|
322 |
+
switch ( $mode ) {
|
323 |
+
case CRYPT_HASH_MODE_MHASH:
|
324 |
+
$output = mhash($this->hash, $text);
|
325 |
+
break;
|
326 |
+
case CRYPT_HASH_MODE_HASH:
|
327 |
+
$output = hash($this->hash, $text, true);
|
328 |
+
break;
|
329 |
+
case CRYPT_HASH_MODE_INTERNAL:
|
330 |
+
$output = call_user_func($this->hash, $text);
|
331 |
+
}
|
332 |
+
}
|
333 |
+
|
334 |
+
return substr($output, 0, $this->l);
|
335 |
+
}
|
336 |
+
|
337 |
+
/**
|
338 |
+
* Returns the hash length (in bytes)
|
339 |
+
*
|
340 |
+
* @access public
|
341 |
+
* @return Integer
|
342 |
+
*/
|
343 |
+
function getLength()
|
344 |
+
{
|
345 |
+
return $this->l;
|
346 |
+
}
|
347 |
+
|
348 |
+
/**
|
349 |
+
* Wrapper for MD5
|
350 |
+
*
|
351 |
+
* @access private
|
352 |
+
* @param String $text
|
353 |
+
*/
|
354 |
+
function _md5($m)
|
355 |
+
{
|
356 |
+
return pack('H*', md5($m));
|
357 |
+
}
|
358 |
+
|
359 |
+
/**
|
360 |
+
* Wrapper for SHA1
|
361 |
+
*
|
362 |
+
* @access private
|
363 |
+
* @param String $text
|
364 |
+
*/
|
365 |
+
function _sha1($m)
|
366 |
+
{
|
367 |
+
return pack('H*', sha1($m));
|
368 |
+
}
|
369 |
+
|
370 |
+
/**
|
371 |
+
* Pure-PHP implementation of MD2
|
372 |
+
*
|
373 |
+
* See {@link http://tools.ietf.org/html/rfc1319 RFC1319}.
|
374 |
+
*
|
375 |
+
* @access private
|
376 |
+
* @param String $text
|
377 |
+
*/
|
378 |
+
function _md2($m)
|
379 |
+
{
|
380 |
+
static $s = array(
|
381 |
+
41, 46, 67, 201, 162, 216, 124, 1, 61, 54, 84, 161, 236, 240, 6,
|
382 |
+
19, 98, 167, 5, 243, 192, 199, 115, 140, 152, 147, 43, 217, 188,
|
383 |
+
76, 130, 202, 30, 155, 87, 60, 253, 212, 224, 22, 103, 66, 111, 24,
|
384 |
+
138, 23, 229, 18, 190, 78, 196, 214, 218, 158, 222, 73, 160, 251,
|
385 |
+
245, 142, 187, 47, 238, 122, 169, 104, 121, 145, 21, 178, 7, 63,
|
386 |
+
148, 194, 16, 137, 11, 34, 95, 33, 128, 127, 93, 154, 90, 144, 50,
|
387 |
+
39, 53, 62, 204, 231, 191, 247, 151, 3, 255, 25, 48, 179, 72, 165,
|
388 |
+
181, 209, 215, 94, 146, 42, 172, 86, 170, 198, 79, 184, 56, 210,
|
389 |
+
150, 164, 125, 182, 118, 252, 107, 226, 156, 116, 4, 241, 69, 157,
|
390 |
+
112, 89, 100, 113, 135, 32, 134, 91, 207, 101, 230, 45, 168, 2, 27,
|
391 |
+
96, 37, 173, 174, 176, 185, 246, 28, 70, 97, 105, 52, 64, 126, 15,
|
392 |
+
85, 71, 163, 35, 221, 81, 175, 58, 195, 92, 249, 206, 186, 197,
|
393 |
+
234, 38, 44, 83, 13, 110, 133, 40, 132, 9, 211, 223, 205, 244, 65,
|
394 |
+
129, 77, 82, 106, 220, 55, 200, 108, 193, 171, 250, 36, 225, 123,
|
395 |
+
8, 12, 189, 177, 74, 120, 136, 149, 139, 227, 99, 232, 109, 233,
|
396 |
+
203, 213, 254, 59, 0, 29, 57, 242, 239, 183, 14, 102, 88, 208, 228,
|
397 |
+
166, 119, 114, 248, 235, 117, 75, 10, 49, 68, 80, 180, 143, 237,
|
398 |
+
31, 26, 219, 153, 141, 51, 159, 17, 131, 20
|
399 |
+
);
|
400 |
+
|
401 |
+
// Step 1. Append Padding Bytes
|
402 |
+
$pad = 16 - (strlen($m) & 0xF);
|
403 |
+
$m.= str_repeat(chr($pad), $pad);
|
404 |
+
|
405 |
+
$length = strlen($m);
|
406 |
+
|
407 |
+
// Step 2. Append Checksum
|
408 |
+
$c = str_repeat(chr(0), 16);
|
409 |
+
$l = chr(0);
|
410 |
+
for ($i = 0; $i < $length; $i+= 16) {
|
411 |
+
for ($j = 0; $j < 16; $j++) {
|
412 |
+
// RFC1319 incorrectly states that C[j] should be set to S[c xor L]
|
413 |
+
//$c[$j] = chr($s[ord($m[$i + $j] ^ $l)]);
|
414 |
+
// per <http://www.rfc-editor.org/errata_search.php?rfc=1319>, however, C[j] should be set to S[c xor L] xor C[j]
|
415 |
+
$c[$j] = chr($s[ord($m[$i + $j] ^ $l)] ^ ord($c[$j]));
|
416 |
+
$l = $c[$j];
|
417 |
+
}
|
418 |
+
}
|
419 |
+
$m.= $c;
|
420 |
+
|
421 |
+
$length+= 16;
|
422 |
+
|
423 |
+
// Step 3. Initialize MD Buffer
|
424 |
+
$x = str_repeat(chr(0), 48);
|
425 |
+
|
426 |
+
// Step 4. Process Message in 16-Byte Blocks
|
427 |
+
for ($i = 0; $i < $length; $i+= 16) {
|
428 |
+
for ($j = 0; $j < 16; $j++) {
|
429 |
+
$x[$j + 16] = $m[$i + $j];
|
430 |
+
$x[$j + 32] = $x[$j + 16] ^ $x[$j];
|
431 |
+
}
|
432 |
+
$t = chr(0);
|
433 |
+
for ($j = 0; $j < 18; $j++) {
|
434 |
+
for ($k = 0; $k < 48; $k++) {
|
435 |
+
$x[$k] = $t = $x[$k] ^ chr($s[ord($t)]);
|
436 |
+
//$t = $x[$k] = $x[$k] ^ chr($s[ord($t)]);
|
437 |
+
}
|
438 |
+
$t = chr(ord($t) + $j);
|
439 |
+
}
|
440 |
+
}
|
441 |
+
|
442 |
+
// Step 5. Output
|
443 |
+
return substr($x, 0, 16);
|
444 |
+
}
|
445 |
+
|
446 |
+
/**
|
447 |
+
* Pure-PHP implementation of SHA256
|
448 |
+
*
|
449 |
+
* See {@link http://en.wikipedia.org/wiki/SHA_hash_functions#SHA-256_.28a_SHA-2_variant.29_pseudocode SHA-256 (a SHA-2 variant) pseudocode - Wikipedia}.
|
450 |
+
*
|
451 |
+
* @access private
|
452 |
+
* @param String $text
|
453 |
+
*/
|
454 |
+
function _sha256($m)
|
455 |
+
{
|
456 |
+
if (extension_loaded('suhosin')) {
|
457 |
+
return pack('H*', sha256($m));
|
458 |
+
}
|
459 |
+
|
460 |
+
// Initialize variables
|
461 |
+
$hash = array(
|
462 |
+
0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
|
463 |
+
);
|
464 |
+
// Initialize table of round constants
|
465 |
+
// (first 32 bits of the fractional parts of the cube roots of the first 64 primes 2..311)
|
466 |
+
static $k = array(
|
467 |
+
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
468 |
+
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
469 |
+
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
470 |
+
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
471 |
+
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
472 |
+
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
473 |
+
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
474 |
+
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
475 |
+
);
|
476 |
+
|
477 |
+
// Pre-processing
|
478 |
+
$length = strlen($m);
|
479 |
+
// to round to nearest 56 mod 64, we'll add 64 - (length + (64 - 56)) % 64
|
480 |
+
$m.= str_repeat(chr(0), 64 - (($length + 8) & 0x3F));
|
481 |
+
$m[$length] = chr(0x80);
|
482 |
+
// we don't support hashing strings 512MB long
|
483 |
+
$m.= pack('N2', 0, $length << 3);
|
484 |
+
|
485 |
+
// Process the message in successive 512-bit chunks
|
486 |
+
$chunks = str_split($m, 64);
|
487 |
+
foreach ($chunks as $chunk) {
|
488 |
+
$w = array();
|
489 |
+
for ($i = 0; $i < 16; $i++) {
|
490 |
+
extract(unpack('Ntemp', $this->_string_shift($chunk, 4)));
|
491 |
+
$w[] = $temp;
|
492 |
+
}
|
493 |
+
|
494 |
+
// Extend the sixteen 32-bit words into sixty-four 32-bit words
|
495 |
+
for ($i = 16; $i < 64; $i++) {
|
496 |
+
$s0 = $this->_rightRotate($w[$i - 15], 7) ^
|
497 |
+
$this->_rightRotate($w[$i - 15], 18) ^
|
498 |
+
$this->_rightShift( $w[$i - 15], 3);
|
499 |
+
$s1 = $this->_rightRotate($w[$i - 2], 17) ^
|
500 |
+
$this->_rightRotate($w[$i - 2], 19) ^
|
501 |
+
$this->_rightShift( $w[$i - 2], 10);
|
502 |
+
$w[$i] = $this->_add($w[$i - 16], $s0, $w[$i - 7], $s1);
|
503 |
+
|
504 |
+
}
|
505 |
+
|
506 |
+
// Initialize hash value for this chunk
|
507 |
+
list($a, $b, $c, $d, $e, $f, $g, $h) = $hash;
|
508 |
+
|
509 |
+
// Main loop
|
510 |
+
for ($i = 0; $i < 64; $i++) {
|
511 |
+
$s0 = $this->_rightRotate($a, 2) ^
|
512 |
+
$this->_rightRotate($a, 13) ^
|
513 |
+
$this->_rightRotate($a, 22);
|
514 |
+
$maj = ($a & $b) ^
|
515 |
+
($a & $c) ^
|
516 |
+
($b & $c);
|
517 |
+
$t2 = $this->_add($s0, $maj);
|
518 |
+
|
519 |
+
$s1 = $this->_rightRotate($e, 6) ^
|
520 |
+
$this->_rightRotate($e, 11) ^
|
521 |
+
$this->_rightRotate($e, 25);
|
522 |
+
$ch = ($e & $f) ^
|
523 |
+
($this->_not($e) & $g);
|
524 |
+
$t1 = $this->_add($h, $s1, $ch, $k[$i], $w[$i]);
|
525 |
+
|
526 |
+
$h = $g;
|
527 |
+
$g = $f;
|
528 |
+
$f = $e;
|
529 |
+
$e = $this->_add($d, $t1);
|
530 |
+
$d = $c;
|
531 |
+
$c = $b;
|
532 |
+
$b = $a;
|
533 |
+
$a = $this->_add($t1, $t2);
|
534 |
+
}
|
535 |
+
|
536 |
+
// Add this chunk's hash to result so far
|
537 |
+
$hash = array(
|
538 |
+
$this->_add($hash[0], $a),
|
539 |
+
$this->_add($hash[1], $b),
|
540 |
+
$this->_add($hash[2], $c),
|
541 |
+
$this->_add($hash[3], $d),
|
542 |
+
$this->_add($hash[4], $e),
|
543 |
+
$this->_add($hash[5], $f),
|
544 |
+
$this->_add($hash[6], $g),
|
545 |
+
$this->_add($hash[7], $h)
|
546 |
+
);
|
547 |
+
}
|
548 |
+
|
549 |
+
// Produce the final hash value (big-endian)
|
550 |
+
return pack('N8', $hash[0], $hash[1], $hash[2], $hash[3], $hash[4], $hash[5], $hash[6], $hash[7]);
|
551 |
+
}
|
552 |
+
|
553 |
+
/**
|
554 |
+
* Pure-PHP implementation of SHA384 and SHA512
|
555 |
+
*
|
556 |
+
* @access private
|
557 |
+
* @param String $text
|
558 |
+
*/
|
559 |
+
function _sha512($m)
|
560 |
+
{
|
561 |
+
if (!class_exists('Math_BigInteger')) {
|
562 |
+
require_once('Math/BigInteger.php');
|
563 |
+
}
|
564 |
+
|
565 |
+
static $init384, $init512, $k;
|
566 |
+
|
567 |
+
if (!isset($k)) {
|
568 |
+
// Initialize variables
|
569 |
+
$init384 = array( // initial values for SHA384
|
570 |
+
'cbbb9d5dc1059ed8', '629a292a367cd507', '9159015a3070dd17', '152fecd8f70e5939',
|
571 |
+
'67332667ffc00b31', '8eb44a8768581511', 'db0c2e0d64f98fa7', '47b5481dbefa4fa4'
|
572 |
+
);
|
573 |
+
$init512 = array( // initial values for SHA512
|
574 |
+
'6a09e667f3bcc908', 'bb67ae8584caa73b', '3c6ef372fe94f82b', 'a54ff53a5f1d36f1',
|
575 |
+
'510e527fade682d1', '9b05688c2b3e6c1f', '1f83d9abfb41bd6b', '5be0cd19137e2179'
|
576 |
+
);
|
577 |
+
|
578 |
+
for ($i = 0; $i < 8; $i++) {
|
579 |
+
$init384[$i] = new Math_BigInteger($init384[$i], 16);
|
580 |
+
$init384[$i]->setPrecision(64);
|
581 |
+
$init512[$i] = new Math_BigInteger($init512[$i], 16);
|
582 |
+
$init512[$i]->setPrecision(64);
|
583 |
+
}
|
584 |
+
|
585 |
+
// Initialize table of round constants
|
586 |
+
// (first 64 bits of the fractional parts of the cube roots of the first 80 primes 2..409)
|
587 |
+
$k = array(
|
588 |
+
'428a2f98d728ae22', '7137449123ef65cd', 'b5c0fbcfec4d3b2f', 'e9b5dba58189dbbc',
|
589 |
+
'3956c25bf348b538', '59f111f1b605d019', '923f82a4af194f9b', 'ab1c5ed5da6d8118',
|
590 |
+
'd807aa98a3030242', '12835b0145706fbe', '243185be4ee4b28c', '550c7dc3d5ffb4e2',
|
591 |
+
'72be5d74f27b896f', '80deb1fe3b1696b1', '9bdc06a725c71235', 'c19bf174cf692694',
|
592 |
+
'e49b69c19ef14ad2', 'efbe4786384f25e3', '0fc19dc68b8cd5b5', '240ca1cc77ac9c65',
|
593 |
+
'2de92c6f592b0275', '4a7484aa6ea6e483', '5cb0a9dcbd41fbd4', '76f988da831153b5',
|
594 |
+
'983e5152ee66dfab', 'a831c66d2db43210', 'b00327c898fb213f', 'bf597fc7beef0ee4',
|
595 |
+
'c6e00bf33da88fc2', 'd5a79147930aa725', '06ca6351e003826f', '142929670a0e6e70',
|
596 |
+
'27b70a8546d22ffc', '2e1b21385c26c926', '4d2c6dfc5ac42aed', '53380d139d95b3df',
|
597 |
+
'650a73548baf63de', '766a0abb3c77b2a8', '81c2c92e47edaee6', '92722c851482353b',
|
598 |
+
'a2bfe8a14cf10364', 'a81a664bbc423001', 'c24b8b70d0f89791', 'c76c51a30654be30',
|
599 |
+
'd192e819d6ef5218', 'd69906245565a910', 'f40e35855771202a', '106aa07032bbd1b8',
|
600 |
+
'19a4c116b8d2d0c8', '1e376c085141ab53', '2748774cdf8eeb99', '34b0bcb5e19b48a8',
|
601 |
+
'391c0cb3c5c95a63', '4ed8aa4ae3418acb', '5b9cca4f7763e373', '682e6ff3d6b2b8a3',
|
602 |
+
'748f82ee5defb2fc', '78a5636f43172f60', '84c87814a1f0ab72', '8cc702081a6439ec',
|
603 |
+
'90befffa23631e28', 'a4506cebde82bde9', 'bef9a3f7b2c67915', 'c67178f2e372532b',
|
604 |
+
'ca273eceea26619c', 'd186b8c721c0c207', 'eada7dd6cde0eb1e', 'f57d4f7fee6ed178',
|
605 |
+
'06f067aa72176fba', '0a637dc5a2c898a6', '113f9804bef90dae', '1b710b35131c471b',
|
606 |
+
'28db77f523047d84', '32caab7b40c72493', '3c9ebe0a15c9bebc', '431d67c49c100d4c',
|
607 |
+
'4cc5d4becb3e42b6', '597f299cfc657e2a', '5fcb6fab3ad6faec', '6c44198c4a475817'
|
608 |
+
);
|
609 |
+
|
610 |
+
for ($i = 0; $i < 80; $i++) {
|
611 |
+
$k[$i] = new Math_BigInteger($k[$i], 16);
|
612 |
+
}
|
613 |
+
}
|
614 |
+
|
615 |
+
$hash = $this->l == 48 ? $init384 : $init512;
|
616 |
+
|
617 |
+
// Pre-processing
|
618 |
+
$length = strlen($m);
|
619 |
+
// to round to nearest 112 mod 128, we'll add 128 - (length + (128 - 112)) % 128
|
620 |
+
$m.= str_repeat(chr(0), 128 - (($length + 16) & 0x7F));
|
621 |
+
$m[$length] = chr(0x80);
|
622 |
+
// we don't support hashing strings 512MB long
|
623 |
+
$m.= pack('N4', 0, 0, 0, $length << 3);
|
624 |
+
|
625 |
+
// Process the message in successive 1024-bit chunks
|
626 |
+
$chunks = str_split($m, 128);
|
627 |
+
foreach ($chunks as $chunk) {
|
628 |
+
$w = array();
|
629 |
+
for ($i = 0; $i < 16; $i++) {
|
630 |
+
$temp = new Math_BigInteger($this->_string_shift($chunk, 8), 256);
|
631 |
+
$temp->setPrecision(64);
|
632 |
+
$w[] = $temp;
|
633 |
+
}
|
634 |
+
|
635 |
+
// Extend the sixteen 32-bit words into eighty 32-bit words
|
636 |
+
for ($i = 16; $i < 80; $i++) {
|
637 |
+
$temp = array(
|
638 |
+
$w[$i - 15]->bitwise_rightRotate(1),
|
639 |
+
$w[$i - 15]->bitwise_rightRotate(8),
|
640 |
+
$w[$i - 15]->bitwise_rightShift(7)
|
641 |
+
);
|
642 |
+
$s0 = $temp[0]->bitwise_xor($temp[1]);
|
643 |
+
$s0 = $s0->bitwise_xor($temp[2]);
|
644 |
+
$temp = array(
|
645 |
+
$w[$i - 2]->bitwise_rightRotate(19),
|
646 |
+
$w[$i - 2]->bitwise_rightRotate(61),
|
647 |
+
$w[$i - 2]->bitwise_rightShift(6)
|
648 |
+
);
|
649 |
+
$s1 = $temp[0]->bitwise_xor($temp[1]);
|
650 |
+
$s1 = $s1->bitwise_xor($temp[2]);
|
651 |
+
$w[$i] = $w[$i - 16]->copy();
|
652 |
+
$w[$i] = $w[$i]->add($s0);
|
653 |
+
$w[$i] = $w[$i]->add($w[$i - 7]);
|
654 |
+
$w[$i] = $w[$i]->add($s1);
|
655 |
+
}
|
656 |
+
|
657 |
+
// Initialize hash value for this chunk
|
658 |
+
$a = $hash[0]->copy();
|
659 |
+
$b = $hash[1]->copy();
|
660 |
+
$c = $hash[2]->copy();
|
661 |
+
$d = $hash[3]->copy();
|
662 |
+
$e = $hash[4]->copy();
|
663 |
+
$f = $hash[5]->copy();
|
664 |
+
$g = $hash[6]->copy();
|
665 |
+
$h = $hash[7]->copy();
|
666 |
+
|
667 |
+
// Main loop
|
668 |
+
for ($i = 0; $i < 80; $i++) {
|
669 |
+
$temp = array(
|
670 |
+
$a->bitwise_rightRotate(28),
|
671 |
+
$a->bitwise_rightRotate(34),
|
672 |
+
$a->bitwise_rightRotate(39)
|
673 |
+
);
|
674 |
+
$s0 = $temp[0]->bitwise_xor($temp[1]);
|
675 |
+
$s0 = $s0->bitwise_xor($temp[2]);
|
676 |
+
$temp = array(
|
677 |
+
$a->bitwise_and($b),
|
678 |
+
$a->bitwise_and($c),
|
679 |
+
$b->bitwise_and($c)
|
680 |
+
);
|
681 |
+
$maj = $temp[0]->bitwise_xor($temp[1]);
|
682 |
+
$maj = $maj->bitwise_xor($temp[2]);
|
683 |
+
$t2 = $s0->add($maj);
|
684 |
+
|
685 |
+
$temp = array(
|
686 |
+
$e->bitwise_rightRotate(14),
|
687 |
+
$e->bitwise_rightRotate(18),
|
688 |
+
$e->bitwise_rightRotate(41)
|
689 |
+
);
|
690 |
+
$s1 = $temp[0]->bitwise_xor($temp[1]);
|
691 |
+
$s1 = $s1->bitwise_xor($temp[2]);
|
692 |
+
$temp = array(
|
693 |
+
$e->bitwise_and($f),
|
694 |
+
$g->bitwise_and($e->bitwise_not())
|
695 |
+
);
|
696 |
+
$ch = $temp[0]->bitwise_xor($temp[1]);
|
697 |
+
$t1 = $h->add($s1);
|
698 |
+
$t1 = $t1->add($ch);
|
699 |
+
$t1 = $t1->add($k[$i]);
|
700 |
+
$t1 = $t1->add($w[$i]);
|
701 |
+
|
702 |
+
$h = $g->copy();
|
703 |
+
$g = $f->copy();
|
704 |
+
$f = $e->copy();
|
705 |
+
$e = $d->add($t1);
|
706 |
+
$d = $c->copy();
|
707 |
+
$c = $b->copy();
|
708 |
+
$b = $a->copy();
|
709 |
+
$a = $t1->add($t2);
|
710 |
+
}
|
711 |
+
|
712 |
+
// Add this chunk's hash to result so far
|
713 |
+
$hash = array(
|
714 |
+
$hash[0]->add($a),
|
715 |
+
$hash[1]->add($b),
|
716 |
+
$hash[2]->add($c),
|
717 |
+
$hash[3]->add($d),
|
718 |
+
$hash[4]->add($e),
|
719 |
+
$hash[5]->add($f),
|
720 |
+
$hash[6]->add($g),
|
721 |
+
$hash[7]->add($h)
|
722 |
+
);
|
723 |
+
}
|
724 |
+
|
725 |
+
// Produce the final hash value (big-endian)
|
726 |
+
// (Crypt_Hash::hash() trims the output for hashes but not for HMACs. as such, we trim the output here)
|
727 |
+
$temp = $hash[0]->toBytes() . $hash[1]->toBytes() . $hash[2]->toBytes() . $hash[3]->toBytes() .
|
728 |
+
$hash[4]->toBytes() . $hash[5]->toBytes();
|
729 |
+
if ($this->l != 48) {
|
730 |
+
$temp.= $hash[6]->toBytes() . $hash[7]->toBytes();
|
731 |
+
}
|
732 |
+
|
733 |
+
return $temp;
|
734 |
+
}
|
735 |
+
|
736 |
+
/**
|
737 |
+
* Right Rotate
|
738 |
+
*
|
739 |
+
* @access private
|
740 |
+
* @param Integer $int
|
741 |
+
* @param Integer $amt
|
742 |
+
* @see _sha256()
|
743 |
+
* @return Integer
|
744 |
+
*/
|
745 |
+
function _rightRotate($int, $amt)
|
746 |
+
{
|
747 |
+
$invamt = 32 - $amt;
|
748 |
+
$mask = (1 << $invamt) - 1;
|
749 |
+
return (($int << $invamt) & 0xFFFFFFFF) | (($int >> $amt) & $mask);
|
750 |
+
}
|
751 |
+
|
752 |
+
/**
|
753 |
+
* Right Shift
|
754 |
+
*
|
755 |
+
* @access private
|
756 |
+
* @param Integer $int
|
757 |
+
* @param Integer $amt
|
758 |
+
* @see _sha256()
|
759 |
+
* @return Integer
|
760 |
+
*/
|
761 |
+
function _rightShift($int, $amt)
|
762 |
+
{
|
763 |
+
$mask = (1 << (32 - $amt)) - 1;
|
764 |
+
return ($int >> $amt) & $mask;
|
765 |
+
}
|
766 |
+
|
767 |
+
/**
|
768 |
+
* Not
|
769 |
+
*
|
770 |
+
* @access private
|
771 |
+
* @param Integer $int
|
772 |
+
* @see _sha256()
|
773 |
+
* @return Integer
|
774 |
+
*/
|
775 |
+
function _not($int)
|
776 |
+
{
|
777 |
+
return ~$int & 0xFFFFFFFF;
|
778 |
+
}
|
779 |
+
|
780 |
+
/**
|
781 |
+
* Add
|
782 |
+
*
|
783 |
+
* _sha256() adds multiple unsigned 32-bit integers. Since PHP doesn't support unsigned integers and since the
|
784 |
+
* possibility of overflow exists, care has to be taken. Math_BigInteger() could be used but this should be faster.
|
785 |
+
*
|
786 |
+
* @param String $string
|
787 |
+
* @param optional Integer $index
|
788 |
+
* @return String
|
789 |
+
* @see _sha256()
|
790 |
+
* @access private
|
791 |
+
*/
|
792 |
+
function _add()
|
793 |
+
{
|
794 |
+
static $mod;
|
795 |
+
if (!isset($mod)) {
|
796 |
+
$mod = pow(2, 32);
|
797 |
+
}
|
798 |
+
|
799 |
+
$result = 0;
|
800 |
+
$arguments = func_get_args();
|
801 |
+
foreach ($arguments as $argument) {
|
802 |
+
$result+= $argument < 0 ? ($argument & 0x7FFFFFFF) + 0x80000000 : $argument;
|
803 |
+
}
|
804 |
+
|
805 |
+
return fmod($result, $mod);
|
806 |
+
}
|
807 |
+
|
808 |
+
/**
|
809 |
+
* String Shift
|
810 |
+
*
|
811 |
+
* Inspired by array_shift
|
812 |
+
*
|
813 |
+
* @param String $string
|
814 |
+
* @param optional Integer $index
|
815 |
+
* @return String
|
816 |
+
* @access private
|
817 |
+
*/
|
818 |
+
function _string_shift(&$string, $index = 1)
|
819 |
+
{
|
820 |
+
$substr = substr($string, 0, $index);
|
821 |
+
$string = substr($string, $index);
|
822 |
+
return $substr;
|
823 |
+
}
|
824 |
+
}
|
classes/phpseclib/Crypt/RC4.php
ADDED
@@ -0,0 +1,505 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of RC4.
|
6 |
+
*
|
7 |
+
* Uses mcrypt, if available, and an internal implementation, otherwise.
|
8 |
+
*
|
9 |
+
* PHP versions 4 and 5
|
10 |
+
*
|
11 |
+
* Useful resources are as follows:
|
12 |
+
*
|
13 |
+
* - {@link http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt ARCFOUR Algorithm}
|
14 |
+
* - {@link http://en.wikipedia.org/wiki/RC4 - Wikipedia: RC4}
|
15 |
+
*
|
16 |
+
* RC4 is also known as ARCFOUR or ARC4. The reason is elaborated upon at Wikipedia. This class is named RC4 and not
|
17 |
+
* ARCFOUR or ARC4 because RC4 is how it is refered to in the SSH1 specification.
|
18 |
+
*
|
19 |
+
* Here's a short example of how to use this library:
|
20 |
+
* <code>
|
21 |
+
* <?php
|
22 |
+
* include('Crypt/RC4.php');
|
23 |
+
*
|
24 |
+
* $rc4 = new Crypt_RC4();
|
25 |
+
*
|
26 |
+
* $rc4->setKey('abcdefgh');
|
27 |
+
*
|
28 |
+
* $size = 10 * 1024;
|
29 |
+
* $plaintext = '';
|
30 |
+
* for ($i = 0; $i < $size; $i++) {
|
31 |
+
* $plaintext.= 'a';
|
32 |
+
* }
|
33 |
+
*
|
34 |
+
* echo $rc4->decrypt($rc4->encrypt($plaintext));
|
35 |
+
* ?>
|
36 |
+
* </code>
|
37 |
+
*
|
38 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
39 |
+
* of this software and associated documentation files (the "Software"), to deal
|
40 |
+
* in the Software without restriction, including without limitation the rights
|
41 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
42 |
+
* copies of the Software, and to permit persons to whom the Software is
|
43 |
+
* furnished to do so, subject to the following conditions:
|
44 |
+
*
|
45 |
+
* The above copyright notice and this permission notice shall be included in
|
46 |
+
* all copies or substantial portions of the Software.
|
47 |
+
*
|
48 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
49 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
50 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
51 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
52 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
53 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
54 |
+
* THE SOFTWARE.
|
55 |
+
*
|
56 |
+
* @category Crypt
|
57 |
+
* @package Crypt_RC4
|
58 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
59 |
+
* @copyright MMVII Jim Wigginton
|
60 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
61 |
+
* @version $Id: RC4.php,v 1.8 2009/06/09 04:00:38 terrafrost Exp $
|
62 |
+
* @link http://phpseclib.sourceforge.net
|
63 |
+
*/
|
64 |
+
|
65 |
+
/**#@+
|
66 |
+
* @access private
|
67 |
+
* @see Crypt_RC4::Crypt_RC4()
|
68 |
+
*/
|
69 |
+
/**
|
70 |
+
* Toggles the internal implementation
|
71 |
+
*/
|
72 |
+
define('CRYPT_RC4_MODE_INTERNAL', 1);
|
73 |
+
/**
|
74 |
+
* Toggles the mcrypt implementation
|
75 |
+
*/
|
76 |
+
define('CRYPT_RC4_MODE_MCRYPT', 2);
|
77 |
+
/**#@-*/
|
78 |
+
|
79 |
+
/**#@+
|
80 |
+
* @access private
|
81 |
+
* @see Crypt_RC4::_crypt()
|
82 |
+
*/
|
83 |
+
define('CRYPT_RC4_ENCRYPT', 0);
|
84 |
+
define('CRYPT_RC4_DECRYPT', 1);
|
85 |
+
/**#@-*/
|
86 |
+
|
87 |
+
/**
|
88 |
+
* Pure-PHP implementation of RC4.
|
89 |
+
*
|
90 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
91 |
+
* @version 0.1.0
|
92 |
+
* @access public
|
93 |
+
* @package Crypt_RC4
|
94 |
+
*/
|
95 |
+
class Crypt_RC4 {
|
96 |
+
/**
|
97 |
+
* The Key
|
98 |
+
*
|
99 |
+
* @see Crypt_RC4::setKey()
|
100 |
+
* @var String
|
101 |
+
* @access private
|
102 |
+
*/
|
103 |
+
var $key = "\0";
|
104 |
+
|
105 |
+
/**
|
106 |
+
* The Key Stream for encryption
|
107 |
+
*
|
108 |
+
* If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
|
109 |
+
*
|
110 |
+
* @see Crypt_RC4::setKey()
|
111 |
+
* @var Array
|
112 |
+
* @access private
|
113 |
+
*/
|
114 |
+
var $encryptStream = false;
|
115 |
+
|
116 |
+
/**
|
117 |
+
* The Key Stream for decryption
|
118 |
+
*
|
119 |
+
* If CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT, this will be equal to the mcrypt object
|
120 |
+
*
|
121 |
+
* @see Crypt_RC4::setKey()
|
122 |
+
* @var Array
|
123 |
+
* @access private
|
124 |
+
*/
|
125 |
+
var $decryptStream = false;
|
126 |
+
|
127 |
+
/**
|
128 |
+
* The $i and $j indexes for encryption
|
129 |
+
*
|
130 |
+
* @see Crypt_RC4::_crypt()
|
131 |
+
* @var Integer
|
132 |
+
* @access private
|
133 |
+
*/
|
134 |
+
var $encryptIndex = 0;
|
135 |
+
|
136 |
+
/**
|
137 |
+
* The $i and $j indexes for decryption
|
138 |
+
*
|
139 |
+
* @see Crypt_RC4::_crypt()
|
140 |
+
* @var Integer
|
141 |
+
* @access private
|
142 |
+
*/
|
143 |
+
var $decryptIndex = 0;
|
144 |
+
|
145 |
+
/**
|
146 |
+
* MCrypt parameters
|
147 |
+
*
|
148 |
+
* @see Crypt_RC4::setMCrypt()
|
149 |
+
* @var Array
|
150 |
+
* @access private
|
151 |
+
*/
|
152 |
+
var $mcrypt = array('', '');
|
153 |
+
|
154 |
+
/**
|
155 |
+
* The Encryption Algorithm
|
156 |
+
*
|
157 |
+
* Only used if CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT. Only possible values are MCRYPT_RC4 or MCRYPT_ARCFOUR.
|
158 |
+
*
|
159 |
+
* @see Crypt_RC4::Crypt_RC4()
|
160 |
+
* @var Integer
|
161 |
+
* @access private
|
162 |
+
*/
|
163 |
+
var $mode;
|
164 |
+
|
165 |
+
/**
|
166 |
+
* Continuous Buffer status
|
167 |
+
*
|
168 |
+
* @see Crypt_RC4::enableContinuousBuffer()
|
169 |
+
* @var Boolean
|
170 |
+
* @access private
|
171 |
+
*/
|
172 |
+
var $continuousBuffer = false;
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Default Constructor.
|
176 |
+
*
|
177 |
+
* Determines whether or not the mcrypt extension should be used.
|
178 |
+
*
|
179 |
+
* @param optional Integer $mode
|
180 |
+
* @return Crypt_RC4
|
181 |
+
* @access public
|
182 |
+
*/
|
183 |
+
function Crypt_RC4()
|
184 |
+
{
|
185 |
+
if ( !defined('CRYPT_RC4_MODE') ) {
|
186 |
+
switch (true) {
|
187 |
+
case extension_loaded('mcrypt') && (defined('MCRYPT_ARCFOUR') || defined('MCRYPT_RC4')):
|
188 |
+
// i'd check to see if rc4 was supported, by doing in_array('arcfour', mcrypt_list_algorithms('')),
|
189 |
+
// but since that can be changed after the object has been created, there doesn't seem to be
|
190 |
+
// a lot of point...
|
191 |
+
define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_MCRYPT);
|
192 |
+
break;
|
193 |
+
default:
|
194 |
+
define('CRYPT_RC4_MODE', CRYPT_RC4_MODE_INTERNAL);
|
195 |
+
}
|
196 |
+
}
|
197 |
+
|
198 |
+
switch ( CRYPT_RC4_MODE ) {
|
199 |
+
case CRYPT_RC4_MODE_MCRYPT:
|
200 |
+
switch (true) {
|
201 |
+
case defined('MCRYPT_ARCFOUR'):
|
202 |
+
$this->mode = MCRYPT_ARCFOUR;
|
203 |
+
break;
|
204 |
+
case defined('MCRYPT_RC4');
|
205 |
+
$this->mode = MCRYPT_RC4;
|
206 |
+
}
|
207 |
+
}
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Sets the key.
|
212 |
+
*
|
213 |
+
* Keys can be between 1 and 256 bytes long. If they are longer then 256 bytes, the first 256 bytes will
|
214 |
+
* be used. If no key is explicitly set, it'll be assumed to be a single null byte.
|
215 |
+
*
|
216 |
+
* @access public
|
217 |
+
* @param String $key
|
218 |
+
*/
|
219 |
+
function setKey($key)
|
220 |
+
{
|
221 |
+
$this->key = $key;
|
222 |
+
|
223 |
+
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
|
224 |
+
return;
|
225 |
+
}
|
226 |
+
|
227 |
+
$keyLength = strlen($key);
|
228 |
+
$keyStream = array();
|
229 |
+
for ($i = 0; $i < 256; $i++) {
|
230 |
+
$keyStream[$i] = $i;
|
231 |
+
}
|
232 |
+
$j = 0;
|
233 |
+
for ($i = 0; $i < 256; $i++) {
|
234 |
+
$j = ($j + $keyStream[$i] + ord($key[$i % $keyLength])) & 255;
|
235 |
+
$temp = $keyStream[$i];
|
236 |
+
$keyStream[$i] = $keyStream[$j];
|
237 |
+
$keyStream[$j] = $temp;
|
238 |
+
}
|
239 |
+
|
240 |
+
$this->encryptIndex = $this->decryptIndex = array(0, 0);
|
241 |
+
$this->encryptStream = $this->decryptStream = $keyStream;
|
242 |
+
}
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Dummy function.
|
246 |
+
*
|
247 |
+
* Some protocols, such as WEP, prepend an "initialization vector" to the key, effectively creating a new key [1].
|
248 |
+
* If you need to use an initialization vector in this manner, feel free to prepend it to the key, yourself, before
|
249 |
+
* calling setKey().
|
250 |
+
*
|
251 |
+
* [1] WEP's initialization vectors (IV's) are used in a somewhat insecure way. Since, in that protocol,
|
252 |
+
* the IV's are relatively easy to predict, an attack described by
|
253 |
+
* {@link http://www.drizzle.com/~aboba/IEEE/rc4_ksaproc.pdf Scott Fluhrer, Itsik Mantin, and Adi Shamir}
|
254 |
+
* can be used to quickly guess at the rest of the key. The following links elaborate:
|
255 |
+
*
|
256 |
+
* {@link http://www.rsa.com/rsalabs/node.asp?id=2009 http://www.rsa.com/rsalabs/node.asp?id=2009}
|
257 |
+
* {@link http://en.wikipedia.org/wiki/Related_key_attack http://en.wikipedia.org/wiki/Related_key_attack}
|
258 |
+
*
|
259 |
+
* @param String $iv
|
260 |
+
* @see Crypt_RC4::setKey()
|
261 |
+
* @access public
|
262 |
+
*/
|
263 |
+
function setIV($iv)
|
264 |
+
{
|
265 |
+
}
|
266 |
+
|
267 |
+
/**
|
268 |
+
* Sets MCrypt parameters. (optional)
|
269 |
+
*
|
270 |
+
* If MCrypt is being used, empty strings will be used, unless otherwise specified.
|
271 |
+
*
|
272 |
+
* @link http://php.net/function.mcrypt-module-open#function.mcrypt-module-open
|
273 |
+
* @access public
|
274 |
+
* @param optional Integer $algorithm_directory
|
275 |
+
* @param optional Integer $mode_directory
|
276 |
+
*/
|
277 |
+
function setMCrypt($algorithm_directory = '', $mode_directory = '')
|
278 |
+
{
|
279 |
+
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
|
280 |
+
$this->mcrypt = array($algorithm_directory, $mode_directory);
|
281 |
+
$this->_closeMCrypt();
|
282 |
+
}
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Encrypts a message.
|
287 |
+
*
|
288 |
+
* @see Crypt_RC4::_crypt()
|
289 |
+
* @access public
|
290 |
+
* @param String $plaintext
|
291 |
+
*/
|
292 |
+
function encrypt($plaintext)
|
293 |
+
{
|
294 |
+
return $this->_crypt($plaintext, CRYPT_RC4_ENCRYPT);
|
295 |
+
}
|
296 |
+
|
297 |
+
/**
|
298 |
+
* Decrypts a message.
|
299 |
+
*
|
300 |
+
* $this->decrypt($this->encrypt($plaintext)) == $this->encrypt($this->encrypt($plaintext)).
|
301 |
+
* Atleast if the continuous buffer is disabled.
|
302 |
+
*
|
303 |
+
* @see Crypt_RC4::_crypt()
|
304 |
+
* @access public
|
305 |
+
* @param String $ciphertext
|
306 |
+
*/
|
307 |
+
function decrypt($ciphertext)
|
308 |
+
{
|
309 |
+
return $this->_crypt($ciphertext, CRYPT_RC4_DECRYPT);
|
310 |
+
}
|
311 |
+
|
312 |
+
/**
|
313 |
+
* Encrypts or decrypts a message.
|
314 |
+
*
|
315 |
+
* @see Crypt_RC4::encrypt()
|
316 |
+
* @see Crypt_RC4::decrypt()
|
317 |
+
* @access private
|
318 |
+
* @param String $text
|
319 |
+
* @param Integer $mode
|
320 |
+
*/
|
321 |
+
function _crypt($text, $mode)
|
322 |
+
{
|
323 |
+
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
|
324 |
+
$keyStream = $mode == CRYPT_RC4_ENCRYPT ? 'encryptStream' : 'decryptStream';
|
325 |
+
|
326 |
+
if ($this->$keyStream === false) {
|
327 |
+
$this->$keyStream = mcrypt_module_open($this->mode, $this->mcrypt[0], MCRYPT_MODE_STREAM, $this->mcrypt[1]);
|
328 |
+
mcrypt_generic_init($this->$keyStream, $this->key, '');
|
329 |
+
} else if (!$this->continuousBuffer) {
|
330 |
+
mcrypt_generic_init($this->$keyStream, $this->key, '');
|
331 |
+
}
|
332 |
+
$newText = mcrypt_generic($this->$keyStream, $text);
|
333 |
+
if (!$this->continuousBuffer) {
|
334 |
+
mcrypt_generic_deinit($this->$keyStream);
|
335 |
+
}
|
336 |
+
|
337 |
+
return $newText;
|
338 |
+
}
|
339 |
+
|
340 |
+
if ($this->encryptStream === false) {
|
341 |
+
$this->setKey($this->key);
|
342 |
+
}
|
343 |
+
|
344 |
+
switch ($mode) {
|
345 |
+
case CRYPT_RC4_ENCRYPT:
|
346 |
+
$keyStream = $this->encryptStream;
|
347 |
+
list($i, $j) = $this->encryptIndex;
|
348 |
+
break;
|
349 |
+
case CRYPT_RC4_DECRYPT:
|
350 |
+
$keyStream = $this->decryptStream;
|
351 |
+
list($i, $j) = $this->decryptIndex;
|
352 |
+
}
|
353 |
+
|
354 |
+
$newText = '';
|
355 |
+
for ($k = 0; $k < strlen($text); $k++) {
|
356 |
+
$i = ($i + 1) & 255;
|
357 |
+
$j = ($j + $keyStream[$i]) & 255;
|
358 |
+
$temp = $keyStream[$i];
|
359 |
+
$keyStream[$i] = $keyStream[$j];
|
360 |
+
$keyStream[$j] = $temp;
|
361 |
+
$temp = $keyStream[($keyStream[$i] + $keyStream[$j]) & 255];
|
362 |
+
$newText.= chr(ord($text[$k]) ^ $temp);
|
363 |
+
}
|
364 |
+
|
365 |
+
if ($this->continuousBuffer) {
|
366 |
+
switch ($mode) {
|
367 |
+
case CRYPT_RC4_ENCRYPT:
|
368 |
+
$this->encryptStream = $keyStream;
|
369 |
+
$this->encryptIndex = array($i, $j);
|
370 |
+
break;
|
371 |
+
case CRYPT_RC4_DECRYPT:
|
372 |
+
$this->decryptStream = $keyStream;
|
373 |
+
$this->decryptIndex = array($i, $j);
|
374 |
+
}
|
375 |
+
}
|
376 |
+
|
377 |
+
return $newText;
|
378 |
+
}
|
379 |
+
|
380 |
+
/**
|
381 |
+
* Treat consecutive "packets" as if they are a continuous buffer.
|
382 |
+
*
|
383 |
+
* Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
|
384 |
+
* will yield different outputs:
|
385 |
+
*
|
386 |
+
* <code>
|
387 |
+
* echo $rc4->encrypt(substr($plaintext, 0, 8));
|
388 |
+
* echo $rc4->encrypt(substr($plaintext, 8, 8));
|
389 |
+
* </code>
|
390 |
+
* <code>
|
391 |
+
* echo $rc4->encrypt($plaintext);
|
392 |
+
* </code>
|
393 |
+
*
|
394 |
+
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
|
395 |
+
* another, as demonstrated with the following:
|
396 |
+
*
|
397 |
+
* <code>
|
398 |
+
* $rc4->encrypt(substr($plaintext, 0, 8));
|
399 |
+
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
400 |
+
* </code>
|
401 |
+
* <code>
|
402 |
+
* echo $rc4->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
403 |
+
* </code>
|
404 |
+
*
|
405 |
+
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
|
406 |
+
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
|
407 |
+
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
|
408 |
+
*
|
409 |
+
* Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
|
410 |
+
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
|
411 |
+
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
|
412 |
+
* however, they are also less intuitive and more likely to cause you problems.
|
413 |
+
*
|
414 |
+
* @see Crypt_RC4::disableContinuousBuffer()
|
415 |
+
* @access public
|
416 |
+
*/
|
417 |
+
function enableContinuousBuffer()
|
418 |
+
{
|
419 |
+
$this->continuousBuffer = true;
|
420 |
+
}
|
421 |
+
|
422 |
+
/**
|
423 |
+
* Treat consecutive packets as if they are a discontinuous buffer.
|
424 |
+
*
|
425 |
+
* The default behavior.
|
426 |
+
*
|
427 |
+
* @see Crypt_RC4::enableContinuousBuffer()
|
428 |
+
* @access public
|
429 |
+
*/
|
430 |
+
function disableContinuousBuffer()
|
431 |
+
{
|
432 |
+
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_INTERNAL ) {
|
433 |
+
$this->encryptIndex = $this->decryptIndex = array(0, 0);
|
434 |
+
$this->setKey($this->key);
|
435 |
+
}
|
436 |
+
|
437 |
+
$this->continuousBuffer = false;
|
438 |
+
}
|
439 |
+
|
440 |
+
/**
|
441 |
+
* Dummy function.
|
442 |
+
*
|
443 |
+
* Since RC4 is a stream cipher and not a block cipher, no padding is necessary. The only reason this function is
|
444 |
+
* included is so that you can switch between a block cipher and a stream cipher transparently.
|
445 |
+
*
|
446 |
+
* @see Crypt_RC4::disablePadding()
|
447 |
+
* @access public
|
448 |
+
*/
|
449 |
+
function enablePadding()
|
450 |
+
{
|
451 |
+
}
|
452 |
+
|
453 |
+
/**
|
454 |
+
* Dummy function.
|
455 |
+
*
|
456 |
+
* @see Crypt_RC4::enablePadding()
|
457 |
+
* @access public
|
458 |
+
*/
|
459 |
+
function disablePadding()
|
460 |
+
{
|
461 |
+
}
|
462 |
+
|
463 |
+
/**
|
464 |
+
* Class destructor.
|
465 |
+
*
|
466 |
+
* Will be called, automatically, if you're using PHP5. If you're using PHP4, call it yourself. Only really
|
467 |
+
* needs to be called if mcrypt is being used.
|
468 |
+
*
|
469 |
+
* @access public
|
470 |
+
*/
|
471 |
+
function __destruct()
|
472 |
+
{
|
473 |
+
if ( CRYPT_RC4_MODE == CRYPT_RC4_MODE_MCRYPT ) {
|
474 |
+
$this->_closeMCrypt();
|
475 |
+
}
|
476 |
+
}
|
477 |
+
|
478 |
+
/**
|
479 |
+
* Properly close the MCrypt objects.
|
480 |
+
*
|
481 |
+
* @access prviate
|
482 |
+
*/
|
483 |
+
function _closeMCrypt()
|
484 |
+
{
|
485 |
+
if ( $this->encryptStream !== false ) {
|
486 |
+
if ( $this->continuousBuffer ) {
|
487 |
+
mcrypt_generic_deinit($this->encryptStream);
|
488 |
+
}
|
489 |
+
|
490 |
+
mcrypt_module_close($this->encryptStream);
|
491 |
+
|
492 |
+
$this->encryptStream = false;
|
493 |
+
}
|
494 |
+
|
495 |
+
if ( $this->decryptStream !== false ) {
|
496 |
+
if ( $this->continuousBuffer ) {
|
497 |
+
mcrypt_generic_deinit($this->decryptStream);
|
498 |
+
}
|
499 |
+
|
500 |
+
mcrypt_module_close($this->decryptStream);
|
501 |
+
|
502 |
+
$this->decryptStream = false;
|
503 |
+
}
|
504 |
+
}
|
505 |
+
}
|
classes/phpseclib/Crypt/RSA.php
ADDED
@@ -0,0 +1,2356 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP PKCS#1 (v2.1) compliant implementation of RSA.
|
6 |
+
*
|
7 |
+
* PHP versions 4 and 5
|
8 |
+
*
|
9 |
+
* Here's an example of how to encrypt and decrypt text with this library:
|
10 |
+
* <code>
|
11 |
+
* <?php
|
12 |
+
* include('Crypt/RSA.php');
|
13 |
+
*
|
14 |
+
* $rsa = new Crypt_RSA();
|
15 |
+
* extract($rsa->createKey());
|
16 |
+
*
|
17 |
+
* $plaintext = 'terrafrost';
|
18 |
+
*
|
19 |
+
* $rsa->loadKey($privatekey);
|
20 |
+
* $ciphertext = $rsa->encrypt($plaintext);
|
21 |
+
*
|
22 |
+
* $rsa->loadKey($publickey);
|
23 |
+
* echo $rsa->decrypt($ciphertext);
|
24 |
+
* ?>
|
25 |
+
* </code>
|
26 |
+
*
|
27 |
+
* Here's an example of how to create signatures and verify signatures with this library:
|
28 |
+
* <code>
|
29 |
+
* <?php
|
30 |
+
* include('Crypt/RSA.php');
|
31 |
+
*
|
32 |
+
* $rsa = new Crypt_RSA();
|
33 |
+
* extract($rsa->createKey());
|
34 |
+
*
|
35 |
+
* $plaintext = 'terrafrost';
|
36 |
+
*
|
37 |
+
* $rsa->loadKey($privatekey);
|
38 |
+
* $signature = $rsa->sign($plaintext);
|
39 |
+
*
|
40 |
+
* $rsa->loadKey($publickey);
|
41 |
+
* echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
|
42 |
+
* ?>
|
43 |
+
* </code>
|
44 |
+
*
|
45 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
46 |
+
* of this software and associated documentation files (the "Software"), to deal
|
47 |
+
* in the Software without restriction, including without limitation the rights
|
48 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
49 |
+
* copies of the Software, and to permit persons to whom the Software is
|
50 |
+
* furnished to do so, subject to the following conditions:
|
51 |
+
*
|
52 |
+
* The above copyright notice and this permission notice shall be included in
|
53 |
+
* all copies or substantial portions of the Software.
|
54 |
+
*
|
55 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
56 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
57 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
58 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
59 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
60 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
61 |
+
* THE SOFTWARE.
|
62 |
+
*
|
63 |
+
* @category Crypt
|
64 |
+
* @package Crypt_RSA
|
65 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
66 |
+
* @copyright MMIX Jim Wigginton
|
67 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
68 |
+
* @version $Id: RSA.php,v 1.19 2010/09/12 21:58:54 terrafrost Exp $
|
69 |
+
* @link http://phpseclib.sourceforge.net
|
70 |
+
*/
|
71 |
+
|
72 |
+
/**
|
73 |
+
* Include Math_BigInteger
|
74 |
+
*/
|
75 |
+
require_once('Math/BigInteger.php');
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Include Crypt_Random
|
79 |
+
*/
|
80 |
+
require_once('Crypt/Random.php');
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Include Crypt_Hash
|
84 |
+
*/
|
85 |
+
require_once('Crypt/Hash.php');
|
86 |
+
|
87 |
+
/**#@+
|
88 |
+
* @access public
|
89 |
+
* @see Crypt_RSA::encrypt()
|
90 |
+
* @see Crypt_RSA::decrypt()
|
91 |
+
*/
|
92 |
+
/**
|
93 |
+
* Use {@link http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding Optimal Asymmetric Encryption Padding}
|
94 |
+
* (OAEP) for encryption / decryption.
|
95 |
+
*
|
96 |
+
* Uses sha1 by default.
|
97 |
+
*
|
98 |
+
* @see Crypt_RSA::setHash()
|
99 |
+
* @see Crypt_RSA::setMGFHash()
|
100 |
+
*/
|
101 |
+
define('CRYPT_RSA_ENCRYPTION_OAEP', 1);
|
102 |
+
/**
|
103 |
+
* Use PKCS#1 padding.
|
104 |
+
*
|
105 |
+
* Although CRYPT_RSA_ENCRYPTION_OAEP offers more security, including PKCS#1 padding is necessary for purposes of backwards
|
106 |
+
* compatability with protocols (like SSH-1) written before OAEP's introduction.
|
107 |
+
*/
|
108 |
+
define('CRYPT_RSA_ENCRYPTION_PKCS1', 2);
|
109 |
+
/**#@-*/
|
110 |
+
|
111 |
+
/**#@+
|
112 |
+
* @access public
|
113 |
+
* @see Crypt_RSA::sign()
|
114 |
+
* @see Crypt_RSA::verify()
|
115 |
+
* @see Crypt_RSA::setHash()
|
116 |
+
*/
|
117 |
+
/**
|
118 |
+
* Use the Probabilistic Signature Scheme for signing
|
119 |
+
*
|
120 |
+
* Uses sha1 by default.
|
121 |
+
*
|
122 |
+
* @see Crypt_RSA::setSaltLength()
|
123 |
+
* @see Crypt_RSA::setMGFHash()
|
124 |
+
*/
|
125 |
+
define('CRYPT_RSA_SIGNATURE_PSS', 1);
|
126 |
+
/**
|
127 |
+
* Use the PKCS#1 scheme by default.
|
128 |
+
*
|
129 |
+
* Although CRYPT_RSA_SIGNATURE_PSS offers more security, including PKCS#1 signing is necessary for purposes of backwards
|
130 |
+
* compatability with protocols (like SSH-2) written before PSS's introduction.
|
131 |
+
*/
|
132 |
+
define('CRYPT_RSA_SIGNATURE_PKCS1', 2);
|
133 |
+
/**#@-*/
|
134 |
+
|
135 |
+
/**#@+
|
136 |
+
* @access private
|
137 |
+
* @see Crypt_RSA::createKey()
|
138 |
+
*/
|
139 |
+
/**
|
140 |
+
* ASN1 Integer
|
141 |
+
*/
|
142 |
+
define('CRYPT_RSA_ASN1_INTEGER', 2);
|
143 |
+
/**
|
144 |
+
* ASN1 Sequence (with the constucted bit set)
|
145 |
+
*/
|
146 |
+
define('CRYPT_RSA_ASN1_SEQUENCE', 48);
|
147 |
+
/**#@-*/
|
148 |
+
|
149 |
+
/**#@+
|
150 |
+
* @access private
|
151 |
+
* @see Crypt_RSA::Crypt_RSA()
|
152 |
+
*/
|
153 |
+
/**
|
154 |
+
* To use the pure-PHP implementation
|
155 |
+
*/
|
156 |
+
define('CRYPT_RSA_MODE_INTERNAL', 1);
|
157 |
+
/**
|
158 |
+
* To use the OpenSSL library
|
159 |
+
*
|
160 |
+
* (if enabled; otherwise, the internal implementation will be used)
|
161 |
+
*/
|
162 |
+
define('CRYPT_RSA_MODE_OPENSSL', 2);
|
163 |
+
/**#@-*/
|
164 |
+
|
165 |
+
/**#@+
|
166 |
+
* @access public
|
167 |
+
* @see Crypt_RSA::createKey()
|
168 |
+
* @see Crypt_RSA::setPrivateKeyFormat()
|
169 |
+
*/
|
170 |
+
/**
|
171 |
+
* PKCS#1 formatted private key
|
172 |
+
*
|
173 |
+
* Used by OpenSSH
|
174 |
+
*/
|
175 |
+
define('CRYPT_RSA_PRIVATE_FORMAT_PKCS1', 0);
|
176 |
+
/**
|
177 |
+
* PuTTY formatted private key
|
178 |
+
*/
|
179 |
+
define('CRYPT_RSA_PRIVATE_FORMAT_PUTTY', 1);
|
180 |
+
/**
|
181 |
+
* XML formatted private key
|
182 |
+
*/
|
183 |
+
define('CRYPT_RSA_PRIVATE_FORMAT_XML', 2);
|
184 |
+
/**#@-*/
|
185 |
+
|
186 |
+
/**#@+
|
187 |
+
* @access public
|
188 |
+
* @see Crypt_RSA::createKey()
|
189 |
+
* @see Crypt_RSA::setPublicKeyFormat()
|
190 |
+
*/
|
191 |
+
/**
|
192 |
+
* Raw public key
|
193 |
+
*
|
194 |
+
* An array containing two Math_BigInteger objects.
|
195 |
+
*
|
196 |
+
* The exponent can be indexed with any of the following:
|
197 |
+
*
|
198 |
+
* 0, e, exponent, publicExponent
|
199 |
+
*
|
200 |
+
* The modulus can be indexed with any of the following:
|
201 |
+
*
|
202 |
+
* 1, n, modulo, modulus
|
203 |
+
*/
|
204 |
+
define('CRYPT_RSA_PUBLIC_FORMAT_RAW', 3);
|
205 |
+
/**
|
206 |
+
* PKCS#1 formatted public key
|
207 |
+
*/
|
208 |
+
define('CRYPT_RSA_PUBLIC_FORMAT_PKCS1', 4);
|
209 |
+
/**
|
210 |
+
* XML formatted public key
|
211 |
+
*/
|
212 |
+
define('CRYPT_RSA_PUBLIC_FORMAT_XML', 5);
|
213 |
+
/**
|
214 |
+
* OpenSSH formatted public key
|
215 |
+
*
|
216 |
+
* Place in $HOME/.ssh/authorized_keys
|
217 |
+
*/
|
218 |
+
define('CRYPT_RSA_PUBLIC_FORMAT_OPENSSH', 6);
|
219 |
+
/**#@-*/
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Pure-PHP PKCS#1 compliant implementation of RSA.
|
223 |
+
*
|
224 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
225 |
+
* @version 0.1.0
|
226 |
+
* @access public
|
227 |
+
* @package Crypt_RSA
|
228 |
+
*/
|
229 |
+
class Crypt_RSA {
|
230 |
+
/**
|
231 |
+
* Precomputed Zero
|
232 |
+
*
|
233 |
+
* @var Array
|
234 |
+
* @access private
|
235 |
+
*/
|
236 |
+
var $zero;
|
237 |
+
|
238 |
+
/**
|
239 |
+
* Precomputed One
|
240 |
+
*
|
241 |
+
* @var Array
|
242 |
+
* @access private
|
243 |
+
*/
|
244 |
+
var $one;
|
245 |
+
|
246 |
+
/**
|
247 |
+
* Private Key Format
|
248 |
+
*
|
249 |
+
* @var Integer
|
250 |
+
* @access private
|
251 |
+
*/
|
252 |
+
var $privateKeyFormat = CRYPT_RSA_PRIVATE_FORMAT_PKCS1;
|
253 |
+
|
254 |
+
/**
|
255 |
+
* Public Key Format
|
256 |
+
*
|
257 |
+
* @var Integer
|
258 |
+
* @access public
|
259 |
+
*/
|
260 |
+
var $publicKeyFormat = CRYPT_RSA_PUBLIC_FORMAT_PKCS1;
|
261 |
+
|
262 |
+
/**
|
263 |
+
* Modulus (ie. n)
|
264 |
+
*
|
265 |
+
* @var Math_BigInteger
|
266 |
+
* @access private
|
267 |
+
*/
|
268 |
+
var $modulus;
|
269 |
+
|
270 |
+
/**
|
271 |
+
* Modulus length
|
272 |
+
*
|
273 |
+
* @var Math_BigInteger
|
274 |
+
* @access private
|
275 |
+
*/
|
276 |
+
var $k;
|
277 |
+
|
278 |
+
/**
|
279 |
+
* Exponent (ie. e or d)
|
280 |
+
*
|
281 |
+
* @var Math_BigInteger
|
282 |
+
* @access private
|
283 |
+
*/
|
284 |
+
var $exponent;
|
285 |
+
|
286 |
+
/**
|
287 |
+
* Primes for Chinese Remainder Theorem (ie. p and q)
|
288 |
+
*
|
289 |
+
* @var Array
|
290 |
+
* @access private
|
291 |
+
*/
|
292 |
+
var $primes;
|
293 |
+
|
294 |
+
/**
|
295 |
+
* Exponents for Chinese Remainder Theorem (ie. dP and dQ)
|
296 |
+
*
|
297 |
+
* @var Array
|
298 |
+
* @access private
|
299 |
+
*/
|
300 |
+
var $exponents;
|
301 |
+
|
302 |
+
/**
|
303 |
+
* Coefficients for Chinese Remainder Theorem (ie. qInv)
|
304 |
+
*
|
305 |
+
* @var Array
|
306 |
+
* @access private
|
307 |
+
*/
|
308 |
+
var $coefficients;
|
309 |
+
|
310 |
+
/**
|
311 |
+
* Hash name
|
312 |
+
*
|
313 |
+
* @var String
|
314 |
+
* @access private
|
315 |
+
*/
|
316 |
+
var $hashName;
|
317 |
+
|
318 |
+
/**
|
319 |
+
* Hash function
|
320 |
+
*
|
321 |
+
* @var Crypt_Hash
|
322 |
+
* @access private
|
323 |
+
*/
|
324 |
+
var $hash;
|
325 |
+
|
326 |
+
/**
|
327 |
+
* Length of hash function output
|
328 |
+
*
|
329 |
+
* @var Integer
|
330 |
+
* @access private
|
331 |
+
*/
|
332 |
+
var $hLen;
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Length of salt
|
336 |
+
*
|
337 |
+
* @var Integer
|
338 |
+
* @access private
|
339 |
+
*/
|
340 |
+
var $sLen;
|
341 |
+
|
342 |
+
/**
|
343 |
+
* Hash function for the Mask Generation Function
|
344 |
+
*
|
345 |
+
* @var Crypt_Hash
|
346 |
+
* @access private
|
347 |
+
*/
|
348 |
+
var $mgfHash;
|
349 |
+
|
350 |
+
/**
|
351 |
+
* Length of MGF hash function output
|
352 |
+
*
|
353 |
+
* @var Integer
|
354 |
+
* @access private
|
355 |
+
*/
|
356 |
+
var $mgfHLen;
|
357 |
+
|
358 |
+
/**
|
359 |
+
* Encryption mode
|
360 |
+
*
|
361 |
+
* @var Integer
|
362 |
+
* @access private
|
363 |
+
*/
|
364 |
+
var $encryptionMode = CRYPT_RSA_ENCRYPTION_OAEP;
|
365 |
+
|
366 |
+
/**
|
367 |
+
* Signature mode
|
368 |
+
*
|
369 |
+
* @var Integer
|
370 |
+
* @access private
|
371 |
+
*/
|
372 |
+
var $signatureMode = CRYPT_RSA_SIGNATURE_PSS;
|
373 |
+
|
374 |
+
/**
|
375 |
+
* Public Exponent
|
376 |
+
*
|
377 |
+
* @var Mixed
|
378 |
+
* @access private
|
379 |
+
*/
|
380 |
+
var $publicExponent = false;
|
381 |
+
|
382 |
+
/**
|
383 |
+
* Password
|
384 |
+
*
|
385 |
+
* @var String
|
386 |
+
* @access private
|
387 |
+
*/
|
388 |
+
var $password = '';
|
389 |
+
|
390 |
+
/**
|
391 |
+
* Components
|
392 |
+
*
|
393 |
+
* For use with parsing XML formatted keys. PHP's XML Parser functions use utilized - instead of PHP's DOM functions -
|
394 |
+
* because PHP's XML Parser functions work on PHP4 whereas PHP's DOM functions - although surperior - don't.
|
395 |
+
*
|
396 |
+
* @see Crypt_RSA::_start_element_handler()
|
397 |
+
* @var Array
|
398 |
+
* @access private
|
399 |
+
*/
|
400 |
+
var $components = array();
|
401 |
+
|
402 |
+
/**
|
403 |
+
* Current String
|
404 |
+
*
|
405 |
+
* For use with parsing XML formatted keys.
|
406 |
+
*
|
407 |
+
* @see Crypt_RSA::_character_handler()
|
408 |
+
* @see Crypt_RSA::_stop_element_handler()
|
409 |
+
* @var Mixed
|
410 |
+
* @access private
|
411 |
+
*/
|
412 |
+
var $current;
|
413 |
+
|
414 |
+
/**
|
415 |
+
* The constructor
|
416 |
+
*
|
417 |
+
* If you want to make use of the openssl extension, you'll need to set the mode manually, yourself. The reason
|
418 |
+
* Crypt_RSA doesn't do it is because OpenSSL doesn't fail gracefully. openssl_pkey_new(), in particular, requires
|
419 |
+
* openssl.cnf be present somewhere and, unfortunately, the only real way to find out is too late.
|
420 |
+
*
|
421 |
+
* @return Crypt_RSA
|
422 |
+
* @access public
|
423 |
+
*/
|
424 |
+
function Crypt_RSA()
|
425 |
+
{
|
426 |
+
if ( !defined('CRYPT_RSA_MODE') ) {
|
427 |
+
switch (true) {
|
428 |
+
//case extension_loaded('openssl') && version_compare(PHP_VERSION, '4.2.0', '>='):
|
429 |
+
// define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_OPENSSL);
|
430 |
+
// break;
|
431 |
+
default:
|
432 |
+
define('CRYPT_RSA_MODE', CRYPT_RSA_MODE_INTERNAL);
|
433 |
+
}
|
434 |
+
}
|
435 |
+
|
436 |
+
$this->zero = new Math_BigInteger();
|
437 |
+
$this->one = new Math_BigInteger(1);
|
438 |
+
|
439 |
+
$this->hash = new Crypt_Hash('sha1');
|
440 |
+
$this->hLen = $this->hash->getLength();
|
441 |
+
$this->hashName = 'sha1';
|
442 |
+
$this->mgfHash = new Crypt_Hash('sha1');
|
443 |
+
$this->mgfHLen = $this->mgfHash->getLength();
|
444 |
+
}
|
445 |
+
|
446 |
+
/**
|
447 |
+
* Create public / private key pair
|
448 |
+
*
|
449 |
+
* Returns an array with the following three elements:
|
450 |
+
* - 'privatekey': The private key.
|
451 |
+
* - 'publickey': The public key.
|
452 |
+
* - 'partialkey': A partially computed key (if the execution time exceeded $timeout).
|
453 |
+
* Will need to be passed back to Crypt_RSA::createKey() as the third parameter for further processing.
|
454 |
+
*
|
455 |
+
* @access public
|
456 |
+
* @param optional Integer $bits
|
457 |
+
* @param optional Integer $timeout
|
458 |
+
* @param optional Math_BigInteger $p
|
459 |
+
*/
|
460 |
+
function createKey($bits = 1024, $timeout = false, $partial = array())
|
461 |
+
{
|
462 |
+
if ( CRYPT_RSA_MODE == CRYPT_RSA_MODE_OPENSSL ) {
|
463 |
+
$rsa = openssl_pkey_new(array('private_key_bits' => $bits));
|
464 |
+
openssl_pkey_export($rsa, $privatekey);
|
465 |
+
$publickey = openssl_pkey_get_details($rsa);
|
466 |
+
$publickey = $publickey['key'];
|
467 |
+
|
468 |
+
if ($this->privateKeyFormat != CRYPT_RSA_PRIVATE_FORMAT_PKCS1) {
|
469 |
+
$privatekey = call_user_func_array(array($this, '_convertPrivateKey'), array_values($this->_parseKey($privatekey, CRYPT_RSA_PRIVATE_FORMAT_PKCS1)));
|
470 |
+
$publickey = call_user_func_array(array($this, '_convertPublicKey'), array_values($this->_parseKey($publickey, CRYPT_RSA_PUBLIC_FORMAT_PKCS1)));
|
471 |
+
}
|
472 |
+
|
473 |
+
return array(
|
474 |
+
'privatekey' => $privatekey,
|
475 |
+
'publickey' => $publickey,
|
476 |
+
'partialkey' => false
|
477 |
+
);
|
478 |
+
}
|
479 |
+
|
480 |
+
static $e;
|
481 |
+
if (!isset($e)) {
|
482 |
+
if (!defined('CRYPT_RSA_EXPONENT')) {
|
483 |
+
// http://en.wikipedia.org/wiki/65537_%28number%29
|
484 |
+
define('CRYPT_RSA_EXPONENT', '65537');
|
485 |
+
}
|
486 |
+
if (!defined('CRYPT_RSA_COMMENT')) {
|
487 |
+
define('CRYPT_RSA_COMMENT', 'phpseclib-generated-key');
|
488 |
+
}
|
489 |
+
// per <http://cseweb.ucsd.edu/~hovav/dist/survey.pdf#page=5>, this number ought not result in primes smaller
|
490 |
+
// than 256 bits.
|
491 |
+
if (!defined('CRYPT_RSA_SMALLEST_PRIME')) {
|
492 |
+
define('CRYPT_RSA_SMALLEST_PRIME', 4096);
|
493 |
+
}
|
494 |
+
|
495 |
+
$e = new Math_BigInteger(CRYPT_RSA_EXPONENT);
|
496 |
+
}
|
497 |
+
|
498 |
+
extract($this->_generateMinMax($bits));
|
499 |
+
$absoluteMin = $min;
|
500 |
+
$temp = $bits >> 1;
|
501 |
+
if ($temp > CRYPT_RSA_SMALLEST_PRIME) {
|
502 |
+
$num_primes = floor($bits / CRYPT_RSA_SMALLEST_PRIME);
|
503 |
+
$temp = CRYPT_RSA_SMALLEST_PRIME;
|
504 |
+
} else {
|
505 |
+
$num_primes = 2;
|
506 |
+
}
|
507 |
+
extract($this->_generateMinMax($temp + $bits % $temp));
|
508 |
+
$finalMax = $max;
|
509 |
+
extract($this->_generateMinMax($temp));
|
510 |
+
|
511 |
+
$generator = new Math_BigInteger();
|
512 |
+
$generator->setRandomGenerator('crypt_random');
|
513 |
+
|
514 |
+
$n = $this->one->copy();
|
515 |
+
if (!empty($partial)) {
|
516 |
+
extract(unserialize($partial));
|
517 |
+
} else {
|
518 |
+
$exponents = $coefficients = $primes = array();
|
519 |
+
$lcm = array(
|
520 |
+
'top' => $this->one->copy(),
|
521 |
+
'bottom' => false
|
522 |
+
);
|
523 |
+
}
|
524 |
+
|
525 |
+
$start = time();
|
526 |
+
$i0 = count($primes) + 1;
|
527 |
+
|
528 |
+
do {
|
529 |
+
for ($i = $i0; $i <= $num_primes; $i++) {
|
530 |
+
if ($timeout !== false) {
|
531 |
+
$timeout-= time() - $start;
|
532 |
+
$start = time();
|
533 |
+
if ($timeout <= 0) {
|
534 |
+
return array(
|
535 |
+
'privatekey' => '',
|
536 |
+
'publickey' => '',
|
537 |
+
'partialkey' => serialize(array(
|
538 |
+
'primes' => $primes,
|
539 |
+
'coefficients' => $coefficients,
|
540 |
+
'lcm' => $lcm,
|
541 |
+
'exponents' => $exponents
|
542 |
+
))
|
543 |
+
);
|
544 |
+
}
|
545 |
+
}
|
546 |
+
|
547 |
+
if ($i == $num_primes) {
|
548 |
+
list($min, $temp) = $absoluteMin->divide($n);
|
549 |
+
if (!$temp->equals($this->zero)) {
|
550 |
+
$min = $min->add($this->one); // ie. ceil()
|
551 |
+
}
|
552 |
+
$primes[$i] = $generator->randomPrime($min, $finalMax, $timeout);
|
553 |
+
} else {
|
554 |
+
$primes[$i] = $generator->randomPrime($min, $max, $timeout);
|
555 |
+
}
|
556 |
+
|
557 |
+
if ($primes[$i] === false) { // if we've reached the timeout
|
558 |
+
if (count($primes) > 1) {
|
559 |
+
$partialkey = '';
|
560 |
+
} else {
|
561 |
+
array_pop($primes);
|
562 |
+
$partialkey = serialize(array(
|
563 |
+
'primes' => $primes,
|
564 |
+
'coefficients' => $coefficients,
|
565 |
+
'lcm' => $lcm,
|
566 |
+
'exponents' => $exponents
|
567 |
+
));
|
568 |
+
}
|
569 |
+
|
570 |
+
return array(
|
571 |
+
'privatekey' => '',
|
572 |
+
'publickey' => '',
|
573 |
+
'partialkey' => $partialkey
|
574 |
+
);
|
575 |
+
}
|
576 |
+
|
577 |
+
// the first coefficient is calculated differently from the rest
|
578 |
+
// ie. instead of being $primes[1]->modInverse($primes[2]), it's $primes[2]->modInverse($primes[1])
|
579 |
+
if ($i > 2) {
|
580 |
+
$coefficients[$i] = $n->modInverse($primes[$i]);
|
581 |
+
}
|
582 |
+
|
583 |
+
$n = $n->multiply($primes[$i]);
|
584 |
+
|
585 |
+
$temp = $primes[$i]->subtract($this->one);
|
586 |
+
|
587 |
+
// textbook RSA implementations use Euler's totient function instead of the least common multiple.
|
588 |
+
// see http://en.wikipedia.org/wiki/Euler%27s_totient_function
|
589 |
+
$lcm['top'] = $lcm['top']->multiply($temp);
|
590 |
+
$lcm['bottom'] = $lcm['bottom'] === false ? $temp : $lcm['bottom']->gcd($temp);
|
591 |
+
|
592 |
+
$exponents[$i] = $e->modInverse($temp);
|
593 |
+
}
|
594 |
+
|
595 |
+
list($lcm) = $lcm['top']->divide($lcm['bottom']);
|
596 |
+
$gcd = $lcm->gcd($e);
|
597 |
+
$i0 = 1;
|
598 |
+
} while (!$gcd->equals($this->one));
|
599 |
+
|
600 |
+
$d = $e->modInverse($lcm);
|
601 |
+
|
602 |
+
$coefficients[2] = $primes[2]->modInverse($primes[1]);
|
603 |
+
|
604 |
+
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.2>:
|
605 |
+
// RSAPrivateKey ::= SEQUENCE {
|
606 |
+
// version Version,
|
607 |
+
// modulus INTEGER, -- n
|
608 |
+
// publicExponent INTEGER, -- e
|
609 |
+
// privateExponent INTEGER, -- d
|
610 |
+
// prime1 INTEGER, -- p
|
611 |
+
// prime2 INTEGER, -- q
|
612 |
+
// exponent1 INTEGER, -- d mod (p-1)
|
613 |
+
// exponent2 INTEGER, -- d mod (q-1)
|
614 |
+
// coefficient INTEGER, -- (inverse of q) mod p
|
615 |
+
// otherPrimeInfos OtherPrimeInfos OPTIONAL
|
616 |
+
// }
|
617 |
+
|
618 |
+
return array(
|
619 |
+
'privatekey' => $this->_convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients),
|
620 |
+
'publickey' => $this->_convertPublicKey($n, $e),
|
621 |
+
'partialkey' => false
|
622 |
+
);
|
623 |
+
}
|
624 |
+
|
625 |
+
/**
|
626 |
+
* Convert a private key to the appropriate format.
|
627 |
+
*
|
628 |
+
* @access private
|
629 |
+
* @see setPrivateKeyFormat()
|
630 |
+
* @param String $RSAPrivateKey
|
631 |
+
* @return String
|
632 |
+
*/
|
633 |
+
function _convertPrivateKey($n, $e, $d, $primes, $exponents, $coefficients)
|
634 |
+
{
|
635 |
+
$num_primes = count($primes);
|
636 |
+
$raw = array(
|
637 |
+
'version' => $num_primes == 2 ? chr(0) : chr(1), // two-prime vs. multi
|
638 |
+
'modulus' => $n->toBytes(true),
|
639 |
+
'publicExponent' => $e->toBytes(true),
|
640 |
+
'privateExponent' => $d->toBytes(true),
|
641 |
+
'prime1' => $primes[1]->toBytes(true),
|
642 |
+
'prime2' => $primes[2]->toBytes(true),
|
643 |
+
'exponent1' => $exponents[1]->toBytes(true),
|
644 |
+
'exponent2' => $exponents[2]->toBytes(true),
|
645 |
+
'coefficient' => $coefficients[2]->toBytes(true)
|
646 |
+
);
|
647 |
+
|
648 |
+
// if the format in question does not support multi-prime rsa and multi-prime rsa was used,
|
649 |
+
// call _convertPublicKey() instead.
|
650 |
+
switch ($this->privateKeyFormat) {
|
651 |
+
default: // eg. CRYPT_RSA_PRIVATE_FORMAT_PKCS1
|
652 |
+
$components = array();
|
653 |
+
foreach ($raw as $name => $value) {
|
654 |
+
$components[$name] = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($value)), $value);
|
655 |
+
}
|
656 |
+
|
657 |
+
$RSAPrivateKey = implode('', $components);
|
658 |
+
|
659 |
+
if ($num_primes > 2) {
|
660 |
+
$OtherPrimeInfos = '';
|
661 |
+
for ($i = 3; $i <= $num_primes; $i++) {
|
662 |
+
// OtherPrimeInfos ::= SEQUENCE SIZE(1..MAX) OF OtherPrimeInfo
|
663 |
+
//
|
664 |
+
// OtherPrimeInfo ::= SEQUENCE {
|
665 |
+
// prime INTEGER, -- ri
|
666 |
+
// exponent INTEGER, -- di
|
667 |
+
// coefficient INTEGER -- ti
|
668 |
+
// }
|
669 |
+
$OtherPrimeInfo = pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($primes[$i]->toBytes(true))), $primes[$i]->toBytes(true));
|
670 |
+
$OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($exponents[$i]->toBytes(true))), $exponents[$i]->toBytes(true));
|
671 |
+
$OtherPrimeInfo.= pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($coefficients[$i]->toBytes(true))), $coefficients[$i]->toBytes(true));
|
672 |
+
$OtherPrimeInfos.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfo)), $OtherPrimeInfo);
|
673 |
+
}
|
674 |
+
$RSAPrivateKey.= pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($OtherPrimeInfos)), $OtherPrimeInfos);
|
675 |
+
}
|
676 |
+
|
677 |
+
$RSAPrivateKey = pack('Ca*a*', CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($RSAPrivateKey)), $RSAPrivateKey);
|
678 |
+
|
679 |
+
if (!empty($this->password)) {
|
680 |
+
$iv = $this->_random(8);
|
681 |
+
$symkey = pack('H*', md5($this->password . $iv)); // symkey is short for symmetric key
|
682 |
+
$symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
|
683 |
+
if (!class_exists('Crypt_TripleDES')) {
|
684 |
+
require_once('Crypt/TripleDES.php');
|
685 |
+
}
|
686 |
+
$des = new Crypt_TripleDES();
|
687 |
+
$des->setKey($symkey);
|
688 |
+
$des->setIV($iv);
|
689 |
+
$iv = strtoupper(bin2hex($iv));
|
690 |
+
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
|
691 |
+
"Proc-Type: 4,ENCRYPTED\r\n" .
|
692 |
+
"DEK-Info: DES-EDE3-CBC,$iv\r\n" .
|
693 |
+
"\r\n" .
|
694 |
+
chunk_split(base64_encode($des->encrypt($RSAPrivateKey))) .
|
695 |
+
'-----END RSA PRIVATE KEY-----';
|
696 |
+
} else {
|
697 |
+
$RSAPrivateKey = "-----BEGIN RSA PRIVATE KEY-----\r\n" .
|
698 |
+
chunk_split(base64_encode($RSAPrivateKey)) .
|
699 |
+
'-----END RSA PRIVATE KEY-----';
|
700 |
+
}
|
701 |
+
|
702 |
+
return $RSAPrivateKey;
|
703 |
+
}
|
704 |
+
}
|
705 |
+
|
706 |
+
/**
|
707 |
+
* Convert a public key to the appropriate format
|
708 |
+
*
|
709 |
+
* @access private
|
710 |
+
* @see setPublicKeyFormat()
|
711 |
+
* @param String $RSAPrivateKey
|
712 |
+
* @return String
|
713 |
+
*/
|
714 |
+
function _convertPublicKey($n, $e)
|
715 |
+
{
|
716 |
+
$modulus = $n->toBytes(true);
|
717 |
+
$publicExponent = $e->toBytes(true);
|
718 |
+
|
719 |
+
switch ($this->publicKeyFormat) {
|
720 |
+
case CRYPT_RSA_PUBLIC_FORMAT_RAW:
|
721 |
+
return array('e' => $e->copy(), 'n' => $n->copy());
|
722 |
+
case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
|
723 |
+
// from <http://tools.ietf.org/html/rfc4253#page-15>:
|
724 |
+
// string "ssh-rsa"
|
725 |
+
// mpint e
|
726 |
+
// mpint n
|
727 |
+
$RSAPublicKey = pack('Na*Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publicExponent), $publicExponent, strlen($modulus), $modulus);
|
728 |
+
$RSAPublicKey = 'ssh-rsa ' . base64_encode($RSAPublicKey) . ' ' . CRYPT_RSA_COMMENT;
|
729 |
+
|
730 |
+
return $RSAPublicKey;
|
731 |
+
default: // eg. CRYPT_RSA_PUBLIC_FORMAT_PKCS1
|
732 |
+
// from <http://tools.ietf.org/html/rfc3447#appendix-A.1.1>:
|
733 |
+
// RSAPublicKey ::= SEQUENCE {
|
734 |
+
// modulus INTEGER, -- n
|
735 |
+
// publicExponent INTEGER -- e
|
736 |
+
// }
|
737 |
+
$components = array(
|
738 |
+
'modulus' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($modulus)), $modulus),
|
739 |
+
'publicExponent' => pack('Ca*a*', CRYPT_RSA_ASN1_INTEGER, $this->_encodeLength(strlen($publicExponent)), $publicExponent)
|
740 |
+
);
|
741 |
+
|
742 |
+
$RSAPublicKey = pack('Ca*a*a*',
|
743 |
+
CRYPT_RSA_ASN1_SEQUENCE, $this->_encodeLength(strlen($components['modulus']) + strlen($components['publicExponent'])),
|
744 |
+
$components['modulus'], $components['publicExponent']
|
745 |
+
);
|
746 |
+
|
747 |
+
$RSAPublicKey = "-----BEGIN PUBLIC KEY-----\r\n" .
|
748 |
+
chunk_split(base64_encode($RSAPublicKey)) .
|
749 |
+
'-----END PUBLIC KEY-----';
|
750 |
+
|
751 |
+
return $RSAPublicKey;
|
752 |
+
}
|
753 |
+
}
|
754 |
+
|
755 |
+
/**
|
756 |
+
* Break a public or private key down into its constituant components
|
757 |
+
*
|
758 |
+
* @access private
|
759 |
+
* @see _convertPublicKey()
|
760 |
+
* @see _convertPrivateKey()
|
761 |
+
* @param String $key
|
762 |
+
* @param Integer $type
|
763 |
+
* @return Array
|
764 |
+
*/
|
765 |
+
function _parseKey($key, $type)
|
766 |
+
{
|
767 |
+
switch ($type) {
|
768 |
+
case CRYPT_RSA_PUBLIC_FORMAT_RAW:
|
769 |
+
if (!is_array($key)) {
|
770 |
+
return false;
|
771 |
+
}
|
772 |
+
$components = array();
|
773 |
+
switch (true) {
|
774 |
+
case isset($key['e']):
|
775 |
+
$components['publicExponent'] = $key['e']->copy();
|
776 |
+
break;
|
777 |
+
case isset($key['exponent']):
|
778 |
+
$components['publicExponent'] = $key['exponent']->copy();
|
779 |
+
break;
|
780 |
+
case isset($key['publicExponent']):
|
781 |
+
$components['publicExponent'] = $key['publicExponent']->copy();
|
782 |
+
break;
|
783 |
+
case isset($key[0]):
|
784 |
+
$components['publicExponent'] = $key[0]->copy();
|
785 |
+
}
|
786 |
+
switch (true) {
|
787 |
+
case isset($key['n']):
|
788 |
+
$components['modulus'] = $key['n']->copy();
|
789 |
+
break;
|
790 |
+
case isset($key['modulo']):
|
791 |
+
$components['modulus'] = $key['modulo']->copy();
|
792 |
+
break;
|
793 |
+
case isset($key['modulus']):
|
794 |
+
$components['modulus'] = $key['modulus']->copy();
|
795 |
+
break;
|
796 |
+
case isset($key[1]):
|
797 |
+
$components['modulus'] = $key[1]->copy();
|
798 |
+
}
|
799 |
+
return $components;
|
800 |
+
case CRYPT_RSA_PRIVATE_FORMAT_PKCS1:
|
801 |
+
case CRYPT_RSA_PUBLIC_FORMAT_PKCS1:
|
802 |
+
/* Although PKCS#1 proposes a format that public and private keys can use, encrypting them is
|
803 |
+
"outside the scope" of PKCS#1. PKCS#1 then refers you to PKCS#12 and PKCS#15 if you're wanting to
|
804 |
+
protect private keys, however, that's not what OpenSSL* does. OpenSSL protects private keys by adding
|
805 |
+
two new "fields" to the key - DEK-Info and Proc-Type. These fields are discussed here:
|
806 |
+
|
807 |
+
http://tools.ietf.org/html/rfc1421#section-4.6.1.1
|
808 |
+
http://tools.ietf.org/html/rfc1421#section-4.6.1.3
|
809 |
+
|
810 |
+
DES-EDE3-CBC as an algorithm, however, is not discussed anywhere, near as I can tell.
|
811 |
+
DES-CBC and DES-EDE are discussed in RFC1423, however, DES-EDE3-CBC isn't, nor is its key derivation
|
812 |
+
function. As is, the definitive authority on this encoding scheme isn't the IETF but rather OpenSSL's
|
813 |
+
own implementation. ie. the implementation *is* the standard and any bugs that may exist in that
|
814 |
+
implementation are part of the standard, as well.
|
815 |
+
|
816 |
+
* OpenSSL is the de facto standard. It's utilized by OpenSSH and other projects */
|
817 |
+
if (preg_match('#DEK-Info: (.+),(.+)#', $key, $matches)) {
|
818 |
+
$iv = pack('H*', trim($matches[2]));
|
819 |
+
$symkey = pack('H*', md5($this->password . substr($iv, 0, 8))); // symkey is short for symmetric key
|
820 |
+
$symkey.= substr(pack('H*', md5($symkey . $this->password . $iv)), 0, 8);
|
821 |
+
$ciphertext = preg_replace('#.+(\r|\n|\r\n)\1|[\r\n]|-.+-#s', '', $key);
|
822 |
+
$ciphertext = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $ciphertext) ? base64_decode($ciphertext) : false;
|
823 |
+
if ($ciphertext === false) {
|
824 |
+
$ciphertext = $key;
|
825 |
+
}
|
826 |
+
switch ($matches[1]) {
|
827 |
+
case 'AES-128-CBC':
|
828 |
+
if (!class_exists('Crypt_AES')) {
|
829 |
+
require_once('Crypt/AES.php');
|
830 |
+
}
|
831 |
+
$symkey = substr($symkey, 0, 16);
|
832 |
+
$crypto = new Crypt_AES();
|
833 |
+
break;
|
834 |
+
case 'DES-EDE3-CFB':
|
835 |
+
if (!class_exists('Crypt_TripleDES')) {
|
836 |
+
require_once('Crypt/TripleDES.php');
|
837 |
+
}
|
838 |
+
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CFB);
|
839 |
+
break;
|
840 |
+
case 'DES-EDE3-CBC':
|
841 |
+
if (!class_exists('Crypt_TripleDES')) {
|
842 |
+
require_once('Crypt/TripleDES.php');
|
843 |
+
}
|
844 |
+
$crypto = new Crypt_TripleDES();
|
845 |
+
break;
|
846 |
+
case 'DES-CBC':
|
847 |
+
if (!class_exists('Crypt_DES')) {
|
848 |
+
require_once('Crypt/DES.php');
|
849 |
+
}
|
850 |
+
$crypto = new Crypt_DES();
|
851 |
+
break;
|
852 |
+
default:
|
853 |
+
return false;
|
854 |
+
}
|
855 |
+
$crypto->setKey($symkey);
|
856 |
+
$crypto->setIV($iv);
|
857 |
+
$decoded = $crypto->decrypt($ciphertext);
|
858 |
+
} else {
|
859 |
+
$decoded = preg_replace('#-.+-|[\r\n]#', '', $key);
|
860 |
+
$decoded = preg_match('#^[a-zA-Z\d/+]*={0,2}$#', $decoded) ? base64_decode($decoded) : false;
|
861 |
+
}
|
862 |
+
|
863 |
+
if ($decoded !== false) {
|
864 |
+
$key = $decoded;
|
865 |
+
}
|
866 |
+
|
867 |
+
$components = array();
|
868 |
+
|
869 |
+
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
|
870 |
+
return false;
|
871 |
+
}
|
872 |
+
if ($this->_decodeLength($key) != strlen($key)) {
|
873 |
+
return false;
|
874 |
+
}
|
875 |
+
|
876 |
+
$tag = ord($this->_string_shift($key));
|
877 |
+
if ($tag == CRYPT_RSA_ASN1_SEQUENCE) {
|
878 |
+
/* intended for keys for which OpenSSL's asn1parse returns the following:
|
879 |
+
|
880 |
+
0:d=0 hl=4 l= 290 cons: SEQUENCE
|
881 |
+
4:d=1 hl=2 l= 13 cons: SEQUENCE
|
882 |
+
6:d=2 hl=2 l= 9 prim: OBJECT :rsaEncryption
|
883 |
+
17:d=2 hl=2 l= 0 prim: NULL
|
884 |
+
19:d=1 hl=4 l= 271 prim: BIT STRING */
|
885 |
+
$this->_string_shift($key, $this->_decodeLength($key));
|
886 |
+
$this->_string_shift($key); // skip over the BIT STRING tag
|
887 |
+
$this->_decodeLength($key); // skip over the BIT STRING length
|
888 |
+
// "The initial octet shall encode, as an unsigned binary integer wtih bit 1 as the least significant bit, the number of
|
889 |
+
// unused bits in teh final subsequent octet. The number shall be in the range zero to seven."
|
890 |
+
// -- http://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf (section 8.6.2.2)
|
891 |
+
$this->_string_shift($key);
|
892 |
+
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
|
893 |
+
return false;
|
894 |
+
}
|
895 |
+
if ($this->_decodeLength($key) != strlen($key)) {
|
896 |
+
return false;
|
897 |
+
}
|
898 |
+
$tag = ord($this->_string_shift($key));
|
899 |
+
}
|
900 |
+
if ($tag != CRYPT_RSA_ASN1_INTEGER) {
|
901 |
+
return false;
|
902 |
+
}
|
903 |
+
|
904 |
+
$length = $this->_decodeLength($key);
|
905 |
+
$temp = $this->_string_shift($key, $length);
|
906 |
+
if (strlen($temp) != 1 || ord($temp) > 2) {
|
907 |
+
$components['modulus'] = new Math_BigInteger($temp, -256);
|
908 |
+
$this->_string_shift($key); // skip over CRYPT_RSA_ASN1_INTEGER
|
909 |
+
$length = $this->_decodeLength($key);
|
910 |
+
$components[$type == CRYPT_RSA_PUBLIC_FORMAT_PKCS1 ? 'publicExponent' : 'privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
911 |
+
|
912 |
+
return $components;
|
913 |
+
}
|
914 |
+
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_INTEGER) {
|
915 |
+
return false;
|
916 |
+
}
|
917 |
+
$length = $this->_decodeLength($key);
|
918 |
+
$components['modulus'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
919 |
+
$this->_string_shift($key);
|
920 |
+
$length = $this->_decodeLength($key);
|
921 |
+
$components['publicExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
922 |
+
$this->_string_shift($key);
|
923 |
+
$length = $this->_decodeLength($key);
|
924 |
+
$components['privateExponent'] = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
925 |
+
$this->_string_shift($key);
|
926 |
+
$length = $this->_decodeLength($key);
|
927 |
+
$components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256));
|
928 |
+
$this->_string_shift($key);
|
929 |
+
$length = $this->_decodeLength($key);
|
930 |
+
$components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
931 |
+
$this->_string_shift($key);
|
932 |
+
$length = $this->_decodeLength($key);
|
933 |
+
$components['exponents'] = array(1 => new Math_BigInteger($this->_string_shift($key, $length), -256));
|
934 |
+
$this->_string_shift($key);
|
935 |
+
$length = $this->_decodeLength($key);
|
936 |
+
$components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
937 |
+
$this->_string_shift($key);
|
938 |
+
$length = $this->_decodeLength($key);
|
939 |
+
$components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($key, $length), -256));
|
940 |
+
|
941 |
+
if (!empty($key)) {
|
942 |
+
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
|
943 |
+
return false;
|
944 |
+
}
|
945 |
+
$this->_decodeLength($key);
|
946 |
+
while (!empty($key)) {
|
947 |
+
if (ord($this->_string_shift($key)) != CRYPT_RSA_ASN1_SEQUENCE) {
|
948 |
+
return false;
|
949 |
+
}
|
950 |
+
$this->_decodeLength($key);
|
951 |
+
$key = substr($key, 1);
|
952 |
+
$length = $this->_decodeLength($key);
|
953 |
+
$components['primes'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
954 |
+
$this->_string_shift($key);
|
955 |
+
$length = $this->_decodeLength($key);
|
956 |
+
$components['exponents'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
957 |
+
$this->_string_shift($key);
|
958 |
+
$length = $this->_decodeLength($key);
|
959 |
+
$components['coefficients'][] = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
960 |
+
}
|
961 |
+
}
|
962 |
+
|
963 |
+
return $components;
|
964 |
+
case CRYPT_RSA_PUBLIC_FORMAT_OPENSSH:
|
965 |
+
$key = base64_decode(preg_replace('#^ssh-rsa | .+$#', '', $key));
|
966 |
+
if ($key === false) {
|
967 |
+
return false;
|
968 |
+
}
|
969 |
+
|
970 |
+
$cleanup = substr($key, 0, 11) == "\0\0\0\7ssh-rsa";
|
971 |
+
|
972 |
+
extract(unpack('Nlength', $this->_string_shift($key, 4)));
|
973 |
+
$publicExponent = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
974 |
+
extract(unpack('Nlength', $this->_string_shift($key, 4)));
|
975 |
+
$modulus = new Math_BigInteger($this->_string_shift($key, $length), -256);
|
976 |
+
|
977 |
+
if ($cleanup && strlen($key)) {
|
978 |
+
extract(unpack('Nlength', $this->_string_shift($key, 4)));
|
979 |
+
return array(
|
980 |
+
'modulus' => new Math_BigInteger($this->_string_shift($key, $length), -256),
|
981 |
+
'publicExponent' => $modulus
|
982 |
+
);
|
983 |
+
} else {
|
984 |
+
return array(
|
985 |
+
'modulus' => $modulus,
|
986 |
+
'publicExponent' => $publicExponent
|
987 |
+
);
|
988 |
+
}
|
989 |
+
// http://www.w3.org/TR/xmldsig-core/#sec-RSAKeyValue
|
990 |
+
// http://en.wikipedia.org/wiki/XML_Signature
|
991 |
+
case CRYPT_RSA_PRIVATE_FORMAT_XML:
|
992 |
+
case CRYPT_RSA_PUBLIC_FORMAT_XML:
|
993 |
+
$this->components = array();
|
994 |
+
|
995 |
+
$xml = xml_parser_create('UTF-8');
|
996 |
+
xml_set_object($xml, $this);
|
997 |
+
xml_set_element_handler($xml, '_start_element_handler', '_stop_element_handler');
|
998 |
+
xml_set_character_data_handler($xml, '_data_handler');
|
999 |
+
if (!xml_parse($xml, $key)) {
|
1000 |
+
return false;
|
1001 |
+
}
|
1002 |
+
|
1003 |
+
return $this->components;
|
1004 |
+
// from PuTTY's SSHPUBK.C
|
1005 |
+
case CRYPT_RSA_PRIVATE_FORMAT_PUTTY:
|
1006 |
+
$components = array();
|
1007 |
+
$key = preg_split('#\r\n|\r|\n#', $key);
|
1008 |
+
$type = trim(preg_replace('#PuTTY-User-Key-File-2: (.+)#', '$1', $key[0]));
|
1009 |
+
if ($type != 'ssh-rsa') {
|
1010 |
+
return false;
|
1011 |
+
}
|
1012 |
+
$encryption = trim(preg_replace('#Encryption: (.+)#', '$1', $key[1]));
|
1013 |
+
|
1014 |
+
$publicLength = trim(preg_replace('#Public-Lines: (\d+)#', '$1', $key[3]));
|
1015 |
+
$public = base64_decode(implode('', array_map('trim', array_slice($key, 4, $publicLength))));
|
1016 |
+
$public = substr($public, 11);
|
1017 |
+
extract(unpack('Nlength', $this->_string_shift($public, 4)));
|
1018 |
+
$components['publicExponent'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
|
1019 |
+
extract(unpack('Nlength', $this->_string_shift($public, 4)));
|
1020 |
+
$components['modulus'] = new Math_BigInteger($this->_string_shift($public, $length), -256);
|
1021 |
+
|
1022 |
+
$privateLength = trim(preg_replace('#Private-Lines: (\d+)#', '$1', $key[$publicLength + 4]));
|
1023 |
+
$private = base64_decode(implode('', array_map('trim', array_slice($key, $publicLength + 5, $privateLength))));
|
1024 |
+
|
1025 |
+
switch ($encryption) {
|
1026 |
+
case 'aes256-cbc':
|
1027 |
+
if (!class_exists('Crypt_AES')) {
|
1028 |
+
require_once('Crypt/AES.php');
|
1029 |
+
}
|
1030 |
+
$symkey = '';
|
1031 |
+
$sequence = 0;
|
1032 |
+
while (strlen($symkey) < 32) {
|
1033 |
+
$temp = pack('Na*', $sequence++, $this->password);
|
1034 |
+
$symkey.= pack('H*', sha1($temp));
|
1035 |
+
}
|
1036 |
+
$symkey = substr($symkey, 0, 32);
|
1037 |
+
$crypto = new Crypt_AES();
|
1038 |
+
}
|
1039 |
+
|
1040 |
+
if ($encryption != 'none') {
|
1041 |
+
$crypto->setKey($symkey);
|
1042 |
+
$crypto->disablePadding();
|
1043 |
+
$private = $crypto->decrypt($private);
|
1044 |
+
if ($private === false) {
|
1045 |
+
return false;
|
1046 |
+
}
|
1047 |
+
}
|
1048 |
+
|
1049 |
+
extract(unpack('Nlength', $this->_string_shift($private, 4)));
|
1050 |
+
$components['privateExponent'] = new Math_BigInteger($this->_string_shift($private, $length), -256);
|
1051 |
+
extract(unpack('Nlength', $this->_string_shift($private, 4)));
|
1052 |
+
$components['primes'] = array(1 => new Math_BigInteger($this->_string_shift($private, $length), -256));
|
1053 |
+
extract(unpack('Nlength', $this->_string_shift($private, 4)));
|
1054 |
+
$components['primes'][] = new Math_BigInteger($this->_string_shift($private, $length), -256);
|
1055 |
+
|
1056 |
+
$temp = $components['primes'][1]->subtract($this->one);
|
1057 |
+
$components['exponents'] = array(1 => $components['publicExponent']->modInverse($temp));
|
1058 |
+
$temp = $components['primes'][2]->subtract($this->one);
|
1059 |
+
$components['exponents'][] = $components['publicExponent']->modInverse($temp);
|
1060 |
+
|
1061 |
+
extract(unpack('Nlength', $this->_string_shift($private, 4)));
|
1062 |
+
$components['coefficients'] = array(2 => new Math_BigInteger($this->_string_shift($private, $length), -256));
|
1063 |
+
|
1064 |
+
return $components;
|
1065 |
+
}
|
1066 |
+
}
|
1067 |
+
|
1068 |
+
/**
|
1069 |
+
* Start Element Handler
|
1070 |
+
*
|
1071 |
+
* Called by xml_set_element_handler()
|
1072 |
+
*
|
1073 |
+
* @access private
|
1074 |
+
* @param Resource $parser
|
1075 |
+
* @param String $name
|
1076 |
+
* @param Array $attribs
|
1077 |
+
*/
|
1078 |
+
function _start_element_handler($parser, $name, $attribs)
|
1079 |
+
{
|
1080 |
+
//$name = strtoupper($name);
|
1081 |
+
switch ($name) {
|
1082 |
+
case 'MODULUS':
|
1083 |
+
$this->current = &$this->components['modulus'];
|
1084 |
+
break;
|
1085 |
+
case 'EXPONENT':
|
1086 |
+
$this->current = &$this->components['publicExponent'];
|
1087 |
+
break;
|
1088 |
+
case 'P':
|
1089 |
+
$this->current = &$this->components['primes'][1];
|
1090 |
+
break;
|
1091 |
+
case 'Q':
|
1092 |
+
$this->current = &$this->components['primes'][2];
|
1093 |
+
break;
|
1094 |
+
case 'DP':
|
1095 |
+
$this->current = &$this->components['exponents'][1];
|
1096 |
+
break;
|
1097 |
+
case 'DQ':
|
1098 |
+
$this->current = &$this->components['exponents'][2];
|
1099 |
+
break;
|
1100 |
+
case 'INVERSEQ':
|
1101 |
+
$this->current = &$this->components['coefficients'][2];
|
1102 |
+
break;
|
1103 |
+
case 'D':
|
1104 |
+
$this->current = &$this->components['privateExponent'];
|
1105 |
+
break;
|
1106 |
+
default:
|
1107 |
+
unset($this->current);
|
1108 |
+
}
|
1109 |
+
$this->current = '';
|
1110 |
+
}
|
1111 |
+
|
1112 |
+
/**
|
1113 |
+
* Stop Element Handler
|
1114 |
+
*
|
1115 |
+
* Called by xml_set_element_handler()
|
1116 |
+
*
|
1117 |
+
* @access private
|
1118 |
+
* @param Resource $parser
|
1119 |
+
* @param String $name
|
1120 |
+
*/
|
1121 |
+
function _stop_element_handler($parser, $name)
|
1122 |
+
{
|
1123 |
+
//$name = strtoupper($name);
|
1124 |
+
if ($name == 'RSAKEYVALUE') {
|
1125 |
+
return;
|
1126 |
+
}
|
1127 |
+
$this->current = new Math_BigInteger(base64_decode($this->current), 256);
|
1128 |
+
}
|
1129 |
+
|
1130 |
+
/**
|
1131 |
+
* Data Handler
|
1132 |
+
*
|
1133 |
+
* Called by xml_set_character_data_handler()
|
1134 |
+
*
|
1135 |
+
* @access private
|
1136 |
+
* @param Resource $parser
|
1137 |
+
* @param String $data
|
1138 |
+
*/
|
1139 |
+
function _data_handler($parser, $data)
|
1140 |
+
{
|
1141 |
+
if (!isset($this->current) || is_object($this->current)) {
|
1142 |
+
return;
|
1143 |
+
}
|
1144 |
+
$this->current.= trim($data);
|
1145 |
+
}
|
1146 |
+
|
1147 |
+
/**
|
1148 |
+
* Loads a public or private key
|
1149 |
+
*
|
1150 |
+
* Returns true on success and false on failure (ie. an incorrect password was provided or the key was malformed)
|
1151 |
+
*
|
1152 |
+
* @access public
|
1153 |
+
* @param String $key
|
1154 |
+
* @param Integer $type optional
|
1155 |
+
*/
|
1156 |
+
function loadKey($key, $type = false)
|
1157 |
+
{
|
1158 |
+
if ($type === false) {
|
1159 |
+
$types = array(
|
1160 |
+
CRYPT_RSA_PUBLIC_FORMAT_RAW,
|
1161 |
+
CRYPT_RSA_PRIVATE_FORMAT_PKCS1,
|
1162 |
+
CRYPT_RSA_PRIVATE_FORMAT_XML,
|
1163 |
+
CRYPT_RSA_PRIVATE_FORMAT_PUTTY,
|
1164 |
+
CRYPT_RSA_PUBLIC_FORMAT_OPENSSH
|
1165 |
+
);
|
1166 |
+
foreach ($types as $type) {
|
1167 |
+
$components = $this->_parseKey($key, $type);
|
1168 |
+
if ($components !== false) {
|
1169 |
+
break;
|
1170 |
+
}
|
1171 |
+
}
|
1172 |
+
|
1173 |
+
} else {
|
1174 |
+
$components = $this->_parseKey($key, $type);
|
1175 |
+
}
|
1176 |
+
|
1177 |
+
if ($components === false) {
|
1178 |
+
return false;
|
1179 |
+
}
|
1180 |
+
|
1181 |
+
$this->modulus = $components['modulus'];
|
1182 |
+
$this->k = strlen($this->modulus->toBytes());
|
1183 |
+
$this->exponent = isset($components['privateExponent']) ? $components['privateExponent'] : $components['publicExponent'];
|
1184 |
+
if (isset($components['primes'])) {
|
1185 |
+
$this->primes = $components['primes'];
|
1186 |
+
$this->exponents = $components['exponents'];
|
1187 |
+
$this->coefficients = $components['coefficients'];
|
1188 |
+
$this->publicExponent = $components['publicExponent'];
|
1189 |
+
} else {
|
1190 |
+
$this->primes = array();
|
1191 |
+
$this->exponents = array();
|
1192 |
+
$this->coefficients = array();
|
1193 |
+
$this->publicExponent = false;
|
1194 |
+
}
|
1195 |
+
|
1196 |
+
return true;
|
1197 |
+
}
|
1198 |
+
|
1199 |
+
/**
|
1200 |
+
* Sets the password
|
1201 |
+
*
|
1202 |
+
* Private keys can be encrypted with a password. To unset the password, pass in the empty string or false.
|
1203 |
+
* Or rather, pass in $password such that empty($password) is true.
|
1204 |
+
*
|
1205 |
+
* @see createKey()
|
1206 |
+
* @see loadKey()
|
1207 |
+
* @access public
|
1208 |
+
* @param String $password
|
1209 |
+
*/
|
1210 |
+
function setPassword($password)
|
1211 |
+
{
|
1212 |
+
$this->password = $password;
|
1213 |
+
}
|
1214 |
+
|
1215 |
+
/**
|
1216 |
+
* Defines the public key
|
1217 |
+
*
|
1218 |
+
* Some private key formats define the public exponent and some don't. Those that don't define it are problematic when
|
1219 |
+
* used in certain contexts. For example, in SSH-2, RSA authentication works by sending the public key along with a
|
1220 |
+
* message signed by the private key to the server. The SSH-2 server looks the public key up in an index of public keys
|
1221 |
+
* and if it's present then proceeds to verify the signature. Problem is, if your private key doesn't include the public
|
1222 |
+
* exponent this won't work unless you manually add the public exponent.
|
1223 |
+
*
|
1224 |
+
* Do note that when a new key is loaded the index will be cleared.
|
1225 |
+
*
|
1226 |
+
* Returns true on success, false on failure
|
1227 |
+
*
|
1228 |
+
* @see getPublicKey()
|
1229 |
+
* @access public
|
1230 |
+
* @param String $key
|
1231 |
+
* @param Integer $type optional
|
1232 |
+
* @return Boolean
|
1233 |
+
*/
|
1234 |
+
function setPublicKey($key, $type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
|
1235 |
+
{
|
1236 |
+
$components = $this->_parseKey($key, $type);
|
1237 |
+
|
1238 |
+
if (empty($this->modulus) || !$this->modulus->equals($components['modulus'])) {
|
1239 |
+
user_error('Trying to load a public key? Use loadKey() instead. It\'s called loadKey() and not loadPrivateKey() for a reason.', E_USER_NOTICE);
|
1240 |
+
return false;
|
1241 |
+
}
|
1242 |
+
|
1243 |
+
$this->publicExponent = $components['publicExponent'];
|
1244 |
+
|
1245 |
+
return true;
|
1246 |
+
}
|
1247 |
+
|
1248 |
+
/**
|
1249 |
+
* Returns the public key
|
1250 |
+
*
|
1251 |
+
* The public key is only returned under two circumstances - if the private key had the public key embedded within it
|
1252 |
+
* or if the public key was set via setPublicKey(). If the currently loaded key is supposed to be the public key this
|
1253 |
+
* function won't return it since this library, for the most part, doesn't distinguish between public and private keys.
|
1254 |
+
*
|
1255 |
+
* @see getPublicKey()
|
1256 |
+
* @access public
|
1257 |
+
* @param String $key
|
1258 |
+
* @param Integer $type optional
|
1259 |
+
*/
|
1260 |
+
function getPublicKey($type = CRYPT_RSA_PUBLIC_FORMAT_PKCS1)
|
1261 |
+
{
|
1262 |
+
if (empty($this->modulus) || empty($this->publicExponent)) {
|
1263 |
+
return false;
|
1264 |
+
}
|
1265 |
+
|
1266 |
+
$oldFormat = $this->publicKeyFormat;
|
1267 |
+
$this->publicKeyFormat = $type;
|
1268 |
+
$temp = $this->_convertPublicKey($this->modulus, $this->publicExponent);
|
1269 |
+
$this->publicKeyFormat = $oldFormat;
|
1270 |
+
return $temp;
|
1271 |
+
}
|
1272 |
+
|
1273 |
+
/**
|
1274 |
+
* Generates the smallest and largest numbers requiring $bits bits
|
1275 |
+
*
|
1276 |
+
* @access private
|
1277 |
+
* @param Integer $bits
|
1278 |
+
* @return Array
|
1279 |
+
*/
|
1280 |
+
function _generateMinMax($bits)
|
1281 |
+
{
|
1282 |
+
$bytes = $bits >> 3;
|
1283 |
+
$min = str_repeat(chr(0), $bytes);
|
1284 |
+
$max = str_repeat(chr(0xFF), $bytes);
|
1285 |
+
$msb = $bits & 7;
|
1286 |
+
if ($msb) {
|
1287 |
+
$min = chr(1 << ($msb - 1)) . $min;
|
1288 |
+
$max = chr((1 << $msb) - 1) . $max;
|
1289 |
+
} else {
|
1290 |
+
$min[0] = chr(0x80);
|
1291 |
+
}
|
1292 |
+
|
1293 |
+
return array(
|
1294 |
+
'min' => new Math_BigInteger($min, 256),
|
1295 |
+
'max' => new Math_BigInteger($max, 256)
|
1296 |
+
);
|
1297 |
+
}
|
1298 |
+
|
1299 |
+
/**
|
1300 |
+
* DER-decode the length
|
1301 |
+
*
|
1302 |
+
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
|
1303 |
+
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 � 8.1.3} for more information.
|
1304 |
+
*
|
1305 |
+
* @access private
|
1306 |
+
* @param String $string
|
1307 |
+
* @return Integer
|
1308 |
+
*/
|
1309 |
+
function _decodeLength(&$string)
|
1310 |
+
{
|
1311 |
+
$length = ord($this->_string_shift($string));
|
1312 |
+
if ( $length & 0x80 ) { // definite length, long form
|
1313 |
+
$length&= 0x7F;
|
1314 |
+
$temp = $this->_string_shift($string, $length);
|
1315 |
+
list(, $length) = unpack('N', substr(str_pad($temp, 4, chr(0), STR_PAD_LEFT), -4));
|
1316 |
+
}
|
1317 |
+
return $length;
|
1318 |
+
}
|
1319 |
+
|
1320 |
+
/**
|
1321 |
+
* DER-encode the length
|
1322 |
+
*
|
1323 |
+
* DER supports lengths up to (2**8)**127, however, we'll only support lengths up to (2**8)**4. See
|
1324 |
+
* {@link http://itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf#p=13 X.690 � 8.1.3} for more information.
|
1325 |
+
*
|
1326 |
+
* @access private
|
1327 |
+
* @param Integer $length
|
1328 |
+
* @return String
|
1329 |
+
*/
|
1330 |
+
function _encodeLength($length)
|
1331 |
+
{
|
1332 |
+
if ($length <= 0x7F) {
|
1333 |
+
return chr($length);
|
1334 |
+
}
|
1335 |
+
|
1336 |
+
$temp = ltrim(pack('N', $length), chr(0));
|
1337 |
+
return pack('Ca*', 0x80 | strlen($temp), $temp);
|
1338 |
+
}
|
1339 |
+
|
1340 |
+
/**
|
1341 |
+
* String Shift
|
1342 |
+
*
|
1343 |
+
* Inspired by array_shift
|
1344 |
+
*
|
1345 |
+
* @param String $string
|
1346 |
+
* @param optional Integer $index
|
1347 |
+
* @return String
|
1348 |
+
* @access private
|
1349 |
+
*/
|
1350 |
+
function _string_shift(&$string, $index = 1)
|
1351 |
+
{
|
1352 |
+
$substr = substr($string, 0, $index);
|
1353 |
+
$string = substr($string, $index);
|
1354 |
+
return $substr;
|
1355 |
+
}
|
1356 |
+
|
1357 |
+
/**
|
1358 |
+
* Determines the private key format
|
1359 |
+
*
|
1360 |
+
* @see createKey()
|
1361 |
+
* @access public
|
1362 |
+
* @param Integer $format
|
1363 |
+
*/
|
1364 |
+
function setPrivateKeyFormat($format)
|
1365 |
+
{
|
1366 |
+
$this->privateKeyFormat = $format;
|
1367 |
+
}
|
1368 |
+
|
1369 |
+
/**
|
1370 |
+
* Determines the public key format
|
1371 |
+
*
|
1372 |
+
* @see createKey()
|
1373 |
+
* @access public
|
1374 |
+
* @param Integer $format
|
1375 |
+
*/
|
1376 |
+
function setPublicKeyFormat($format)
|
1377 |
+
{
|
1378 |
+
$this->publicKeyFormat = $format;
|
1379 |
+
}
|
1380 |
+
|
1381 |
+
/**
|
1382 |
+
* Determines which hashing function should be used
|
1383 |
+
*
|
1384 |
+
* Used with signature production / verification and (if the encryption mode is CRYPT_RSA_ENCRYPTION_OAEP) encryption and
|
1385 |
+
* decryption. If $hash isn't supported, sha1 is used.
|
1386 |
+
*
|
1387 |
+
* @access public
|
1388 |
+
* @param String $hash
|
1389 |
+
*/
|
1390 |
+
function setHash($hash)
|
1391 |
+
{
|
1392 |
+
// Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
|
1393 |
+
switch ($hash) {
|
1394 |
+
case 'md2':
|
1395 |
+
case 'md5':
|
1396 |
+
case 'sha1':
|
1397 |
+
case 'sha256':
|
1398 |
+
case 'sha384':
|
1399 |
+
case 'sha512':
|
1400 |
+
$this->hash = new Crypt_Hash($hash);
|
1401 |
+
$this->hashName = $hash;
|
1402 |
+
break;
|
1403 |
+
default:
|
1404 |
+
$this->hash = new Crypt_Hash('sha1');
|
1405 |
+
$this->hashName = 'sha1';
|
1406 |
+
}
|
1407 |
+
$this->hLen = $this->hash->getLength();
|
1408 |
+
}
|
1409 |
+
|
1410 |
+
/**
|
1411 |
+
* Determines which hashing function should be used for the mask generation function
|
1412 |
+
*
|
1413 |
+
* The mask generation function is used by CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_SIGNATURE_PSS and although it's
|
1414 |
+
* best if Hash and MGFHash are set to the same thing this is not a requirement.
|
1415 |
+
*
|
1416 |
+
* @access public
|
1417 |
+
* @param String $hash
|
1418 |
+
*/
|
1419 |
+
function setMGFHash($hash)
|
1420 |
+
{
|
1421 |
+
// Crypt_Hash supports algorithms that PKCS#1 doesn't support. md5-96 and sha1-96, for example.
|
1422 |
+
switch ($hash) {
|
1423 |
+
case 'md2':
|
1424 |
+
case 'md5':
|
1425 |
+
case 'sha1':
|
1426 |
+
case 'sha256':
|
1427 |
+
case 'sha384':
|
1428 |
+
case 'sha512':
|
1429 |
+
$this->mgfHash = new Crypt_Hash($hash);
|
1430 |
+
break;
|
1431 |
+
default:
|
1432 |
+
$this->mgfHash = new Crypt_Hash('sha1');
|
1433 |
+
}
|
1434 |
+
$this->mgfHLen = $this->mgfHash->getLength();
|
1435 |
+
}
|
1436 |
+
|
1437 |
+
/**
|
1438 |
+
* Determines the salt length
|
1439 |
+
*
|
1440 |
+
* To quote from {@link http://tools.ietf.org/html/rfc3447#page-38 RFC3447#page-38}:
|
1441 |
+
*
|
1442 |
+
* Typical salt lengths in octets are hLen (the length of the output
|
1443 |
+
* of the hash function Hash) and 0.
|
1444 |
+
*
|
1445 |
+
* @access public
|
1446 |
+
* @param Integer $format
|
1447 |
+
*/
|
1448 |
+
function setSaltLength($sLen)
|
1449 |
+
{
|
1450 |
+
$this->sLen = $sLen;
|
1451 |
+
}
|
1452 |
+
|
1453 |
+
/**
|
1454 |
+
* Generates a random string x bytes long
|
1455 |
+
*
|
1456 |
+
* @access public
|
1457 |
+
* @param Integer $bytes
|
1458 |
+
* @param optional Integer $nonzero
|
1459 |
+
* @return String
|
1460 |
+
*/
|
1461 |
+
function _random($bytes, $nonzero = false)
|
1462 |
+
{
|
1463 |
+
$temp = '';
|
1464 |
+
if ($nonzero) {
|
1465 |
+
for ($i = 0; $i < $bytes; $i++) {
|
1466 |
+
$temp.= chr(crypt_random(1, 255));
|
1467 |
+
}
|
1468 |
+
} else {
|
1469 |
+
$ints = ($bytes + 1) >> 2;
|
1470 |
+
for ($i = 0; $i < $ints; $i++) {
|
1471 |
+
$temp.= pack('N', crypt_random());
|
1472 |
+
}
|
1473 |
+
$temp = substr($temp, 0, $bytes);
|
1474 |
+
}
|
1475 |
+
return $temp;
|
1476 |
+
}
|
1477 |
+
|
1478 |
+
/**
|
1479 |
+
* Integer-to-Octet-String primitive
|
1480 |
+
*
|
1481 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-4.1 RFC3447#section-4.1}.
|
1482 |
+
*
|
1483 |
+
* @access private
|
1484 |
+
* @param Math_BigInteger $x
|
1485 |
+
* @param Integer $xLen
|
1486 |
+
* @return String
|
1487 |
+
*/
|
1488 |
+
function _i2osp($x, $xLen)
|
1489 |
+
{
|
1490 |
+
$x = $x->toBytes();
|
1491 |
+
if (strlen($x) > $xLen) {
|
1492 |
+
user_error('Integer too large', E_USER_NOTICE);
|
1493 |
+
return false;
|
1494 |
+
}
|
1495 |
+
return str_pad($x, $xLen, chr(0), STR_PAD_LEFT);
|
1496 |
+
}
|
1497 |
+
|
1498 |
+
/**
|
1499 |
+
* Octet-String-to-Integer primitive
|
1500 |
+
*
|
1501 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-4.2 RFC3447#section-4.2}.
|
1502 |
+
*
|
1503 |
+
* @access private
|
1504 |
+
* @param String $x
|
1505 |
+
* @return Math_BigInteger
|
1506 |
+
*/
|
1507 |
+
function _os2ip($x)
|
1508 |
+
{
|
1509 |
+
return new Math_BigInteger($x, 256);
|
1510 |
+
}
|
1511 |
+
|
1512 |
+
/**
|
1513 |
+
* Exponentiate with or without Chinese Remainder Theorem
|
1514 |
+
*
|
1515 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.2}.
|
1516 |
+
*
|
1517 |
+
* @access private
|
1518 |
+
* @param Math_BigInteger $x
|
1519 |
+
* @return Math_BigInteger
|
1520 |
+
*/
|
1521 |
+
function _exponentiate($x)
|
1522 |
+
{
|
1523 |
+
if (empty($this->primes) || empty($this->coefficients) || empty($this->exponents)) {
|
1524 |
+
return $x->modPow($this->exponent, $this->modulus);
|
1525 |
+
}
|
1526 |
+
|
1527 |
+
$num_primes = count($this->primes);
|
1528 |
+
|
1529 |
+
if (defined('CRYPT_RSA_DISABLE_BLINDING')) {
|
1530 |
+
$m_i = array(
|
1531 |
+
1 => $x->modPow($this->exponents[1], $this->primes[1]),
|
1532 |
+
2 => $x->modPow($this->exponents[2], $this->primes[2])
|
1533 |
+
);
|
1534 |
+
$h = $m_i[1]->subtract($m_i[2]);
|
1535 |
+
$h = $h->multiply($this->coefficients[2]);
|
1536 |
+
list(, $h) = $h->divide($this->primes[1]);
|
1537 |
+
$m = $m_i[2]->add($h->multiply($this->primes[2]));
|
1538 |
+
|
1539 |
+
$r = $this->primes[1];
|
1540 |
+
for ($i = 3; $i <= $num_primes; $i++) {
|
1541 |
+
$m_i = $x->modPow($this->exponents[$i], $this->primes[$i]);
|
1542 |
+
|
1543 |
+
$r = $r->multiply($this->primes[$i - 1]);
|
1544 |
+
|
1545 |
+
$h = $m_i->subtract($m);
|
1546 |
+
$h = $h->multiply($this->coefficients[$i]);
|
1547 |
+
list(, $h) = $h->divide($this->primes[$i]);
|
1548 |
+
|
1549 |
+
$m = $m->add($r->multiply($h));
|
1550 |
+
}
|
1551 |
+
} else {
|
1552 |
+
$smallest = $this->primes[1];
|
1553 |
+
for ($i = 2; $i <= $num_primes; $i++) {
|
1554 |
+
if ($smallest->compare($this->primes[$i]) > 0) {
|
1555 |
+
$smallest = $this->primes[$i];
|
1556 |
+
}
|
1557 |
+
}
|
1558 |
+
|
1559 |
+
$one = new Math_BigInteger(1);
|
1560 |
+
$one->setRandomGenerator('crypt_random');
|
1561 |
+
|
1562 |
+
$r = $one->random($one, $smallest->subtract($one));
|
1563 |
+
|
1564 |
+
$m_i = array(
|
1565 |
+
1 => $this->_blind($x, $r, 1),
|
1566 |
+
2 => $this->_blind($x, $r, 2)
|
1567 |
+
);
|
1568 |
+
$h = $m_i[1]->subtract($m_i[2]);
|
1569 |
+
$h = $h->multiply($this->coefficients[2]);
|
1570 |
+
list(, $h) = $h->divide($this->primes[1]);
|
1571 |
+
$m = $m_i[2]->add($h->multiply($this->primes[2]));
|
1572 |
+
|
1573 |
+
$r = $this->primes[1];
|
1574 |
+
for ($i = 3; $i <= $num_primes; $i++) {
|
1575 |
+
$m_i = $this->_blind($x, $r, $i);
|
1576 |
+
|
1577 |
+
$r = $r->multiply($this->primes[$i - 1]);
|
1578 |
+
|
1579 |
+
$h = $m_i->subtract($m);
|
1580 |
+
$h = $h->multiply($this->coefficients[$i]);
|
1581 |
+
list(, $h) = $h->divide($this->primes[$i]);
|
1582 |
+
|
1583 |
+
$m = $m->add($r->multiply($h));
|
1584 |
+
}
|
1585 |
+
}
|
1586 |
+
|
1587 |
+
return $m;
|
1588 |
+
}
|
1589 |
+
|
1590 |
+
/**
|
1591 |
+
* Performs RSA Blinding
|
1592 |
+
*
|
1593 |
+
* Protects against timing attacks by employing RSA Blinding.
|
1594 |
+
* Returns $x->modPow($this->exponents[$i], $this->primes[$i])
|
1595 |
+
*
|
1596 |
+
* @access private
|
1597 |
+
* @param Math_BigInteger $x
|
1598 |
+
* @param Math_BigInteger $r
|
1599 |
+
* @param Integer $i
|
1600 |
+
* @return Math_BigInteger
|
1601 |
+
*/
|
1602 |
+
function _blind($x, $r, $i)
|
1603 |
+
{
|
1604 |
+
$x = $x->multiply($r->modPow($this->publicExponent, $this->primes[$i]));
|
1605 |
+
$x = $x->modPow($this->exponents[$i], $this->primes[$i]);
|
1606 |
+
|
1607 |
+
$r = $r->modInverse($this->primes[$i]);
|
1608 |
+
$x = $x->multiply($r);
|
1609 |
+
list(, $x) = $x->divide($this->primes[$i]);
|
1610 |
+
|
1611 |
+
return $x;
|
1612 |
+
}
|
1613 |
+
|
1614 |
+
/**
|
1615 |
+
* RSAEP
|
1616 |
+
*
|
1617 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-5.1.1 RFC3447#section-5.1.1}.
|
1618 |
+
*
|
1619 |
+
* @access private
|
1620 |
+
* @param Math_BigInteger $m
|
1621 |
+
* @return Math_BigInteger
|
1622 |
+
*/
|
1623 |
+
function _rsaep($m)
|
1624 |
+
{
|
1625 |
+
if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
|
1626 |
+
user_error('Message representative out of range', E_USER_NOTICE);
|
1627 |
+
return false;
|
1628 |
+
}
|
1629 |
+
return $this->_exponentiate($m);
|
1630 |
+
}
|
1631 |
+
|
1632 |
+
/**
|
1633 |
+
* RSADP
|
1634 |
+
*
|
1635 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-5.1.2 RFC3447#section-5.1.2}.
|
1636 |
+
*
|
1637 |
+
* @access private
|
1638 |
+
* @param Math_BigInteger $c
|
1639 |
+
* @return Math_BigInteger
|
1640 |
+
*/
|
1641 |
+
function _rsadp($c)
|
1642 |
+
{
|
1643 |
+
if ($c->compare($this->zero) < 0 || $c->compare($this->modulus) > 0) {
|
1644 |
+
user_error('Ciphertext representative out of range', E_USER_NOTICE);
|
1645 |
+
return false;
|
1646 |
+
}
|
1647 |
+
return $this->_exponentiate($c);
|
1648 |
+
}
|
1649 |
+
|
1650 |
+
/**
|
1651 |
+
* RSASP1
|
1652 |
+
*
|
1653 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-5.2.1 RFC3447#section-5.2.1}.
|
1654 |
+
*
|
1655 |
+
* @access private
|
1656 |
+
* @param Math_BigInteger $m
|
1657 |
+
* @return Math_BigInteger
|
1658 |
+
*/
|
1659 |
+
function _rsasp1($m)
|
1660 |
+
{
|
1661 |
+
if ($m->compare($this->zero) < 0 || $m->compare($this->modulus) > 0) {
|
1662 |
+
user_error('Message representative out of range', E_USER_NOTICE);
|
1663 |
+
return false;
|
1664 |
+
}
|
1665 |
+
return $this->_exponentiate($m);
|
1666 |
+
}
|
1667 |
+
|
1668 |
+
/**
|
1669 |
+
* RSAVP1
|
1670 |
+
*
|
1671 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-5.2.2 RFC3447#section-5.2.2}.
|
1672 |
+
*
|
1673 |
+
* @access private
|
1674 |
+
* @param Math_BigInteger $s
|
1675 |
+
* @return Math_BigInteger
|
1676 |
+
*/
|
1677 |
+
function _rsavp1($s)
|
1678 |
+
{
|
1679 |
+
if ($s->compare($this->zero) < 0 || $s->compare($this->modulus) > 0) {
|
1680 |
+
user_error('Signature representative out of range', E_USER_NOTICE);
|
1681 |
+
return false;
|
1682 |
+
}
|
1683 |
+
return $this->_exponentiate($s);
|
1684 |
+
}
|
1685 |
+
|
1686 |
+
/**
|
1687 |
+
* MGF1
|
1688 |
+
*
|
1689 |
+
* See {@link http://tools.ietf.org/html/rfc3447#appendix-B.2.1 RFC3447#appendix-B.2.1}.
|
1690 |
+
*
|
1691 |
+
* @access private
|
1692 |
+
* @param String $mgfSeed
|
1693 |
+
* @param Integer $mgfLen
|
1694 |
+
* @return String
|
1695 |
+
*/
|
1696 |
+
function _mgf1($mgfSeed, $maskLen)
|
1697 |
+
{
|
1698 |
+
// if $maskLen would yield strings larger than 4GB, PKCS#1 suggests a "Mask too long" error be output.
|
1699 |
+
|
1700 |
+
$t = '';
|
1701 |
+
$count = ceil($maskLen / $this->mgfHLen);
|
1702 |
+
for ($i = 0; $i < $count; $i++) {
|
1703 |
+
$c = pack('N', $i);
|
1704 |
+
$t.= $this->mgfHash->hash($mgfSeed . $c);
|
1705 |
+
}
|
1706 |
+
|
1707 |
+
return substr($t, 0, $maskLen);
|
1708 |
+
}
|
1709 |
+
|
1710 |
+
/**
|
1711 |
+
* RSAES-OAEP-ENCRYPT
|
1712 |
+
*
|
1713 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-7.1.1 RFC3447#section-7.1.1} and
|
1714 |
+
* {http://en.wikipedia.org/wiki/Optimal_Asymmetric_Encryption_Padding OAES}.
|
1715 |
+
*
|
1716 |
+
* @access private
|
1717 |
+
* @param String $m
|
1718 |
+
* @param String $l
|
1719 |
+
* @return String
|
1720 |
+
*/
|
1721 |
+
function _rsaes_oaep_encrypt($m, $l = '')
|
1722 |
+
{
|
1723 |
+
$mLen = strlen($m);
|
1724 |
+
|
1725 |
+
// Length checking
|
1726 |
+
|
1727 |
+
// if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
|
1728 |
+
// be output.
|
1729 |
+
|
1730 |
+
if ($mLen > $this->k - 2 * $this->hLen - 2) {
|
1731 |
+
user_error('Message too long', E_USER_NOTICE);
|
1732 |
+
return false;
|
1733 |
+
}
|
1734 |
+
|
1735 |
+
// EME-OAEP encoding
|
1736 |
+
|
1737 |
+
$lHash = $this->hash->hash($l);
|
1738 |
+
$ps = str_repeat(chr(0), $this->k - $mLen - 2 * $this->hLen - 2);
|
1739 |
+
$db = $lHash . $ps . chr(1) . $m;
|
1740 |
+
$seed = $this->_random($this->hLen);
|
1741 |
+
$dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
|
1742 |
+
$maskedDB = $db ^ $dbMask;
|
1743 |
+
$seedMask = $this->_mgf1($maskedDB, $this->hLen);
|
1744 |
+
$maskedSeed = $seed ^ $seedMask;
|
1745 |
+
$em = chr(0) . $maskedSeed . $maskedDB;
|
1746 |
+
|
1747 |
+
// RSA encryption
|
1748 |
+
|
1749 |
+
$m = $this->_os2ip($em);
|
1750 |
+
$c = $this->_rsaep($m);
|
1751 |
+
$c = $this->_i2osp($c, $this->k);
|
1752 |
+
|
1753 |
+
// Output the ciphertext C
|
1754 |
+
|
1755 |
+
return $c;
|
1756 |
+
}
|
1757 |
+
|
1758 |
+
/**
|
1759 |
+
* RSAES-OAEP-DECRYPT
|
1760 |
+
*
|
1761 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-7.1.2 RFC3447#section-7.1.2}. The fact that the error
|
1762 |
+
* messages aren't distinguishable from one another hinders debugging, but, to quote from RFC3447#section-7.1.2:
|
1763 |
+
*
|
1764 |
+
* Note. Care must be taken to ensure that an opponent cannot
|
1765 |
+
* distinguish the different error conditions in Step 3.g, whether by
|
1766 |
+
* error message or timing, or, more generally, learn partial
|
1767 |
+
* information about the encoded message EM. Otherwise an opponent may
|
1768 |
+
* be able to obtain useful information about the decryption of the
|
1769 |
+
* ciphertext C, leading to a chosen-ciphertext attack such as the one
|
1770 |
+
* observed by Manger [36].
|
1771 |
+
*
|
1772 |
+
* As for $l... to quote from {@link http://tools.ietf.org/html/rfc3447#page-17 RFC3447#page-17}:
|
1773 |
+
*
|
1774 |
+
* Both the encryption and the decryption operations of RSAES-OAEP take
|
1775 |
+
* the value of a label L as input. In this version of PKCS #1, L is
|
1776 |
+
* the empty string; other uses of the label are outside the scope of
|
1777 |
+
* this document.
|
1778 |
+
*
|
1779 |
+
* @access private
|
1780 |
+
* @param String $c
|
1781 |
+
* @param String $l
|
1782 |
+
* @return String
|
1783 |
+
*/
|
1784 |
+
function _rsaes_oaep_decrypt($c, $l = '')
|
1785 |
+
{
|
1786 |
+
// Length checking
|
1787 |
+
|
1788 |
+
// if $l is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
|
1789 |
+
// be output.
|
1790 |
+
|
1791 |
+
if (strlen($c) != $this->k || $this->k < 2 * $this->hLen + 2) {
|
1792 |
+
user_error('Decryption error', E_USER_NOTICE);
|
1793 |
+
return false;
|
1794 |
+
}
|
1795 |
+
|
1796 |
+
// RSA decryption
|
1797 |
+
|
1798 |
+
$c = $this->_os2ip($c);
|
1799 |
+
$m = $this->_rsadp($c);
|
1800 |
+
if ($m === false) {
|
1801 |
+
user_error('Decryption error', E_USER_NOTICE);
|
1802 |
+
return false;
|
1803 |
+
}
|
1804 |
+
$em = $this->_i2osp($m, $this->k);
|
1805 |
+
|
1806 |
+
// EME-OAEP decoding
|
1807 |
+
|
1808 |
+
$lHash = $this->hash->hash($l);
|
1809 |
+
$y = ord($em[0]);
|
1810 |
+
$maskedSeed = substr($em, 1, $this->hLen);
|
1811 |
+
$maskedDB = substr($em, $this->hLen + 1);
|
1812 |
+
$seedMask = $this->_mgf1($maskedDB, $this->hLen);
|
1813 |
+
$seed = $maskedSeed ^ $seedMask;
|
1814 |
+
$dbMask = $this->_mgf1($seed, $this->k - $this->hLen - 1);
|
1815 |
+
$db = $maskedDB ^ $dbMask;
|
1816 |
+
$lHash2 = substr($db, 0, $this->hLen);
|
1817 |
+
$m = substr($db, $this->hLen);
|
1818 |
+
if ($lHash != $lHash2) {
|
1819 |
+
user_error('Decryption error', E_USER_NOTICE);
|
1820 |
+
return false;
|
1821 |
+
}
|
1822 |
+
$m = ltrim($m, chr(0));
|
1823 |
+
if (ord($m[0]) != 1) {
|
1824 |
+
user_error('Decryption error', E_USER_NOTICE);
|
1825 |
+
return false;
|
1826 |
+
}
|
1827 |
+
|
1828 |
+
// Output the message M
|
1829 |
+
|
1830 |
+
return substr($m, 1);
|
1831 |
+
}
|
1832 |
+
|
1833 |
+
/**
|
1834 |
+
* RSAES-PKCS1-V1_5-ENCRYPT
|
1835 |
+
*
|
1836 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-7.2.1 RFC3447#section-7.2.1}.
|
1837 |
+
*
|
1838 |
+
* @access private
|
1839 |
+
* @param String $m
|
1840 |
+
* @return String
|
1841 |
+
*/
|
1842 |
+
function _rsaes_pkcs1_v1_5_encrypt($m)
|
1843 |
+
{
|
1844 |
+
$mLen = strlen($m);
|
1845 |
+
|
1846 |
+
// Length checking
|
1847 |
+
|
1848 |
+
if ($mLen > $this->k - 11) {
|
1849 |
+
user_error('Message too long', E_USER_NOTICE);
|
1850 |
+
return false;
|
1851 |
+
}
|
1852 |
+
|
1853 |
+
// EME-PKCS1-v1_5 encoding
|
1854 |
+
|
1855 |
+
$ps = $this->_random($this->k - $mLen - 3, true);
|
1856 |
+
$em = chr(0) . chr(2) . $ps . chr(0) . $m;
|
1857 |
+
|
1858 |
+
// RSA encryption
|
1859 |
+
$m = $this->_os2ip($em);
|
1860 |
+
$c = $this->_rsaep($m);
|
1861 |
+
$c = $this->_i2osp($c, $this->k);
|
1862 |
+
|
1863 |
+
// Output the ciphertext C
|
1864 |
+
|
1865 |
+
return $c;
|
1866 |
+
}
|
1867 |
+
|
1868 |
+
/**
|
1869 |
+
* RSAES-PKCS1-V1_5-DECRYPT
|
1870 |
+
*
|
1871 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-7.2.2 RFC3447#section-7.2.2}.
|
1872 |
+
*
|
1873 |
+
* For compatability purposes, this function departs slightly from the description given in RFC3447.
|
1874 |
+
* The reason being that RFC2313#section-8.1 (PKCS#1 v1.5) states that ciphertext's encrypted by the
|
1875 |
+
* private key should have the second byte set to either 0 or 1 and that ciphertext's encrypted by the
|
1876 |
+
* public key should have the second byte set to 2. In RFC3447 (PKCS#1 v2.1), the second byte is supposed
|
1877 |
+
* to be 2 regardless of which key is used. for compatability purposes, we'll just check to make sure the
|
1878 |
+
* second byte is 2 or less. If it is, we'll accept the decrypted string as valid.
|
1879 |
+
*
|
1880 |
+
* As a consequence of this, a private key encrypted ciphertext produced with Crypt_RSA may not decrypt
|
1881 |
+
* with a strictly PKCS#1 v1.5 compliant RSA implementation. Public key encrypted ciphertext's should but
|
1882 |
+
* not private key encrypted ciphertext's.
|
1883 |
+
*
|
1884 |
+
* @access private
|
1885 |
+
* @param String $c
|
1886 |
+
* @return String
|
1887 |
+
*/
|
1888 |
+
function _rsaes_pkcs1_v1_5_decrypt($c)
|
1889 |
+
{
|
1890 |
+
// Length checking
|
1891 |
+
|
1892 |
+
if (strlen($c) != $this->k) { // or if k < 11
|
1893 |
+
user_error('Decryption error', E_USER_NOTICE);
|
1894 |
+
return false;
|
1895 |
+
}
|
1896 |
+
|
1897 |
+
// RSA decryption
|
1898 |
+
|
1899 |
+
$c = $this->_os2ip($c);
|
1900 |
+
$m = $this->_rsadp($c);
|
1901 |
+
|
1902 |
+
if ($m === false) {
|
1903 |
+
user_error('Decryption error', E_USER_NOTICE);
|
1904 |
+
return false;
|
1905 |
+
}
|
1906 |
+
$em = $this->_i2osp($m, $this->k);
|
1907 |
+
|
1908 |
+
// EME-PKCS1-v1_5 decoding
|
1909 |
+
|
1910 |
+
if (ord($em[0]) != 0 || ord($em[1]) > 2) {
|
1911 |
+
user_error('Decryption error', E_USER_NOTICE);
|
1912 |
+
return false;
|
1913 |
+
}
|
1914 |
+
|
1915 |
+
$ps = substr($em, 2, strpos($em, chr(0), 2) - 2);
|
1916 |
+
$m = substr($em, strlen($ps) + 3);
|
1917 |
+
|
1918 |
+
if (strlen($ps) < 8) {
|
1919 |
+
user_error('Decryption error', E_USER_NOTICE);
|
1920 |
+
return false;
|
1921 |
+
}
|
1922 |
+
|
1923 |
+
// Output M
|
1924 |
+
|
1925 |
+
return $m;
|
1926 |
+
}
|
1927 |
+
|
1928 |
+
/**
|
1929 |
+
* EMSA-PSS-ENCODE
|
1930 |
+
*
|
1931 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-9.1.1 RFC3447#section-9.1.1}.
|
1932 |
+
*
|
1933 |
+
* @access private
|
1934 |
+
* @param String $m
|
1935 |
+
* @param Integer $emBits
|
1936 |
+
*/
|
1937 |
+
function _emsa_pss_encode($m, $emBits)
|
1938 |
+
{
|
1939 |
+
// if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
|
1940 |
+
// be output.
|
1941 |
+
|
1942 |
+
$emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8)
|
1943 |
+
$sLen = $this->sLen == false ? $this->hLen : $this->sLen;
|
1944 |
+
|
1945 |
+
$mHash = $this->hash->hash($m);
|
1946 |
+
if ($emLen < $this->hLen + $sLen + 2) {
|
1947 |
+
user_error('Encoding error', E_USER_NOTICE);
|
1948 |
+
return false;
|
1949 |
+
}
|
1950 |
+
|
1951 |
+
$salt = $this->_random($sLen);
|
1952 |
+
$m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
|
1953 |
+
$h = $this->hash->hash($m2);
|
1954 |
+
$ps = str_repeat(chr(0), $emLen - $sLen - $this->hLen - 2);
|
1955 |
+
$db = $ps . chr(1) . $salt;
|
1956 |
+
$dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
|
1957 |
+
$maskedDB = $db ^ $dbMask;
|
1958 |
+
$maskedDB[0] = ~chr(0xFF << ($emBits & 7)) & $maskedDB[0];
|
1959 |
+
$em = $maskedDB . $h . chr(0xBC);
|
1960 |
+
|
1961 |
+
return $em;
|
1962 |
+
}
|
1963 |
+
|
1964 |
+
/**
|
1965 |
+
* EMSA-PSS-VERIFY
|
1966 |
+
*
|
1967 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-9.1.2 RFC3447#section-9.1.2}.
|
1968 |
+
*
|
1969 |
+
* @access private
|
1970 |
+
* @param String $m
|
1971 |
+
* @param String $em
|
1972 |
+
* @param Integer $emBits
|
1973 |
+
* @return String
|
1974 |
+
*/
|
1975 |
+
function _emsa_pss_verify($m, $em, $emBits)
|
1976 |
+
{
|
1977 |
+
// if $m is larger than two million terrabytes and you're using sha1, PKCS#1 suggests a "Label too long" error
|
1978 |
+
// be output.
|
1979 |
+
|
1980 |
+
$emLen = ($emBits + 1) >> 3; // ie. ceil($emBits / 8);
|
1981 |
+
$sLen = $this->sLen == false ? $this->hLen : $this->sLen;
|
1982 |
+
|
1983 |
+
$mHash = $this->hash->hash($m);
|
1984 |
+
if ($emLen < $this->hLen + $sLen + 2) {
|
1985 |
+
return false;
|
1986 |
+
}
|
1987 |
+
|
1988 |
+
if ($em[strlen($em) - 1] != chr(0xBC)) {
|
1989 |
+
return false;
|
1990 |
+
}
|
1991 |
+
|
1992 |
+
$maskedDB = substr($em, 0, -$this->hLen - 1);
|
1993 |
+
$h = substr($em, -$this->hLen - 1, $this->hLen);
|
1994 |
+
$temp = chr(0xFF << ($emBits & 7));
|
1995 |
+
if ((~$maskedDB[0] & $temp) != $temp) {
|
1996 |
+
return false;
|
1997 |
+
}
|
1998 |
+
$dbMask = $this->_mgf1($h, $emLen - $this->hLen - 1);
|
1999 |
+
$db = $maskedDB ^ $dbMask;
|
2000 |
+
$db[0] = ~chr(0xFF << ($emBits & 7)) & $db[0];
|
2001 |
+
$temp = $emLen - $this->hLen - $sLen - 2;
|
2002 |
+
if (substr($db, 0, $temp) != str_repeat(chr(0), $temp) || ord($db[$temp]) != 1) {
|
2003 |
+
return false;
|
2004 |
+
}
|
2005 |
+
$salt = substr($db, $temp + 1); // should be $sLen long
|
2006 |
+
$m2 = "\0\0\0\0\0\0\0\0" . $mHash . $salt;
|
2007 |
+
$h2 = $this->hash->hash($m2);
|
2008 |
+
return $h == $h2;
|
2009 |
+
}
|
2010 |
+
|
2011 |
+
/**
|
2012 |
+
* RSASSA-PSS-SIGN
|
2013 |
+
*
|
2014 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-8.1.1 RFC3447#section-8.1.1}.
|
2015 |
+
*
|
2016 |
+
* @access private
|
2017 |
+
* @param String $m
|
2018 |
+
* @return String
|
2019 |
+
*/
|
2020 |
+
function _rsassa_pss_sign($m)
|
2021 |
+
{
|
2022 |
+
// EMSA-PSS encoding
|
2023 |
+
|
2024 |
+
$em = $this->_emsa_pss_encode($m, 8 * $this->k - 1);
|
2025 |
+
|
2026 |
+
// RSA signature
|
2027 |
+
|
2028 |
+
$m = $this->_os2ip($em);
|
2029 |
+
$s = $this->_rsasp1($m);
|
2030 |
+
$s = $this->_i2osp($s, $this->k);
|
2031 |
+
|
2032 |
+
// Output the signature S
|
2033 |
+
|
2034 |
+
return $s;
|
2035 |
+
}
|
2036 |
+
|
2037 |
+
/**
|
2038 |
+
* RSASSA-PSS-VERIFY
|
2039 |
+
*
|
2040 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-8.1.2 RFC3447#section-8.1.2}.
|
2041 |
+
*
|
2042 |
+
* @access private
|
2043 |
+
* @param String $m
|
2044 |
+
* @param String $s
|
2045 |
+
* @return String
|
2046 |
+
*/
|
2047 |
+
function _rsassa_pss_verify($m, $s)
|
2048 |
+
{
|
2049 |
+
// Length checking
|
2050 |
+
|
2051 |
+
if (strlen($s) != $this->k) {
|
2052 |
+
user_error('Invalid signature', E_USER_NOTICE);
|
2053 |
+
return false;
|
2054 |
+
}
|
2055 |
+
|
2056 |
+
// RSA verification
|
2057 |
+
|
2058 |
+
$modBits = 8 * $this->k;
|
2059 |
+
|
2060 |
+
$s2 = $this->_os2ip($s);
|
2061 |
+
$m2 = $this->_rsavp1($s2);
|
2062 |
+
if ($m2 === false) {
|
2063 |
+
user_error('Invalid signature', E_USER_NOTICE);
|
2064 |
+
return false;
|
2065 |
+
}
|
2066 |
+
$em = $this->_i2osp($m2, $modBits >> 3);
|
2067 |
+
if ($em === false) {
|
2068 |
+
user_error('Invalid signature', E_USER_NOTICE);
|
2069 |
+
return false;
|
2070 |
+
}
|
2071 |
+
|
2072 |
+
// EMSA-PSS verification
|
2073 |
+
|
2074 |
+
return $this->_emsa_pss_verify($m, $em, $modBits - 1);
|
2075 |
+
}
|
2076 |
+
|
2077 |
+
/**
|
2078 |
+
* EMSA-PKCS1-V1_5-ENCODE
|
2079 |
+
*
|
2080 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-9.2 RFC3447#section-9.2}.
|
2081 |
+
*
|
2082 |
+
* @access private
|
2083 |
+
* @param String $m
|
2084 |
+
* @param Integer $emLen
|
2085 |
+
* @return String
|
2086 |
+
*/
|
2087 |
+
function _emsa_pkcs1_v1_5_encode($m, $emLen)
|
2088 |
+
{
|
2089 |
+
$h = $this->hash->hash($m);
|
2090 |
+
if ($h === false) {
|
2091 |
+
return false;
|
2092 |
+
}
|
2093 |
+
|
2094 |
+
// see http://tools.ietf.org/html/rfc3447#page-43
|
2095 |
+
switch ($this->hashName) {
|
2096 |
+
case 'md2':
|
2097 |
+
$t = pack('H*', '3020300c06082a864886f70d020205000410');
|
2098 |
+
break;
|
2099 |
+
case 'md5':
|
2100 |
+
$t = pack('H*', '3020300c06082a864886f70d020505000410');
|
2101 |
+
break;
|
2102 |
+
case 'sha1':
|
2103 |
+
$t = pack('H*', '3021300906052b0e03021a05000414');
|
2104 |
+
break;
|
2105 |
+
case 'sha256':
|
2106 |
+
$t = pack('H*', '3031300d060960864801650304020105000420');
|
2107 |
+
break;
|
2108 |
+
case 'sha384':
|
2109 |
+
$t = pack('H*', '3041300d060960864801650304020205000430');
|
2110 |
+
break;
|
2111 |
+
case 'sha512':
|
2112 |
+
$t = pack('H*', '3051300d060960864801650304020305000440');
|
2113 |
+
}
|
2114 |
+
$t.= $h;
|
2115 |
+
$tLen = strlen($t);
|
2116 |
+
|
2117 |
+
if ($emLen < $tLen + 11) {
|
2118 |
+
user_error('Intended encoded message length too short', E_USER_NOTICE);
|
2119 |
+
return false;
|
2120 |
+
}
|
2121 |
+
|
2122 |
+
$ps = str_repeat(chr(0xFF), $emLen - $tLen - 3);
|
2123 |
+
|
2124 |
+
$em = "\0\1$ps\0$t";
|
2125 |
+
|
2126 |
+
return $em;
|
2127 |
+
}
|
2128 |
+
|
2129 |
+
/**
|
2130 |
+
* RSASSA-PKCS1-V1_5-SIGN
|
2131 |
+
*
|
2132 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-8.2.1 RFC3447#section-8.2.1}.
|
2133 |
+
*
|
2134 |
+
* @access private
|
2135 |
+
* @param String $m
|
2136 |
+
* @return String
|
2137 |
+
*/
|
2138 |
+
function _rsassa_pkcs1_v1_5_sign($m)
|
2139 |
+
{
|
2140 |
+
// EMSA-PKCS1-v1_5 encoding
|
2141 |
+
|
2142 |
+
$em = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
|
2143 |
+
if ($em === false) {
|
2144 |
+
user_error('RSA modulus too short', E_USER_NOTICE);
|
2145 |
+
return false;
|
2146 |
+
}
|
2147 |
+
|
2148 |
+
// RSA signature
|
2149 |
+
|
2150 |
+
$m = $this->_os2ip($em);
|
2151 |
+
$s = $this->_rsasp1($m);
|
2152 |
+
$s = $this->_i2osp($s, $this->k);
|
2153 |
+
|
2154 |
+
// Output the signature S
|
2155 |
+
|
2156 |
+
return $s;
|
2157 |
+
}
|
2158 |
+
|
2159 |
+
/**
|
2160 |
+
* RSASSA-PKCS1-V1_5-VERIFY
|
2161 |
+
*
|
2162 |
+
* See {@link http://tools.ietf.org/html/rfc3447#section-8.2.2 RFC3447#section-8.2.2}.
|
2163 |
+
*
|
2164 |
+
* @access private
|
2165 |
+
* @param String $m
|
2166 |
+
* @return String
|
2167 |
+
*/
|
2168 |
+
function _rsassa_pkcs1_v1_5_verify($m, $s)
|
2169 |
+
{
|
2170 |
+
// Length checking
|
2171 |
+
|
2172 |
+
if (strlen($s) != $this->k) {
|
2173 |
+
user_error('Invalid signature', E_USER_NOTICE);
|
2174 |
+
return false;
|
2175 |
+
}
|
2176 |
+
|
2177 |
+
// RSA verification
|
2178 |
+
|
2179 |
+
$s = $this->_os2ip($s);
|
2180 |
+
$m2 = $this->_rsavp1($s);
|
2181 |
+
if ($m2 === false) {
|
2182 |
+
user_error('Invalid signature', E_USER_NOTICE);
|
2183 |
+
return false;
|
2184 |
+
}
|
2185 |
+
$em = $this->_i2osp($m2, $this->k);
|
2186 |
+
if ($em === false) {
|
2187 |
+
user_error('Invalid signature', E_USER_NOTICE);
|
2188 |
+
return false;
|
2189 |
+
}
|
2190 |
+
|
2191 |
+
// EMSA-PKCS1-v1_5 encoding
|
2192 |
+
|
2193 |
+
$em2 = $this->_emsa_pkcs1_v1_5_encode($m, $this->k);
|
2194 |
+
if ($em2 === false) {
|
2195 |
+
user_error('RSA modulus too short', E_USER_NOTICE);
|
2196 |
+
return false;
|
2197 |
+
}
|
2198 |
+
|
2199 |
+
// Compare
|
2200 |
+
|
2201 |
+
return $em === $em2;
|
2202 |
+
}
|
2203 |
+
|
2204 |
+
/**
|
2205 |
+
* Set Encryption Mode
|
2206 |
+
*
|
2207 |
+
* Valid values include CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1.
|
2208 |
+
*
|
2209 |
+
* @access public
|
2210 |
+
* @param Integer $mode
|
2211 |
+
*/
|
2212 |
+
function setEncryptionMode($mode)
|
2213 |
+
{
|
2214 |
+
$this->encryptionMode = $mode;
|
2215 |
+
}
|
2216 |
+
|
2217 |
+
/**
|
2218 |
+
* Set Signature Mode
|
2219 |
+
*
|
2220 |
+
* Valid values include CRYPT_RSA_SIGNATURE_PSS and CRYPT_RSA_SIGNATURE_PKCS1
|
2221 |
+
*
|
2222 |
+
* @access public
|
2223 |
+
* @param Integer $mode
|
2224 |
+
*/
|
2225 |
+
function setSignatureMode($mode)
|
2226 |
+
{
|
2227 |
+
$this->signatureMode = $mode;
|
2228 |
+
}
|
2229 |
+
|
2230 |
+
/**
|
2231 |
+
* Encryption
|
2232 |
+
*
|
2233 |
+
* Both CRYPT_RSA_ENCRYPTION_OAEP and CRYPT_RSA_ENCRYPTION_PKCS1 both place limits on how long $plaintext can be.
|
2234 |
+
* If $plaintext exceeds those limits it will be broken up so that it does and the resultant ciphertext's will
|
2235 |
+
* be concatenated together.
|
2236 |
+
*
|
2237 |
+
* @see decrypt()
|
2238 |
+
* @access public
|
2239 |
+
* @param String $plaintext
|
2240 |
+
* @return String
|
2241 |
+
*/
|
2242 |
+
function encrypt($plaintext)
|
2243 |
+
{
|
2244 |
+
switch ($this->encryptionMode) {
|
2245 |
+
case CRYPT_RSA_ENCRYPTION_PKCS1:
|
2246 |
+
$length = $this->k - 11;
|
2247 |
+
if ($length <= 0) {
|
2248 |
+
return false;
|
2249 |
+
}
|
2250 |
+
|
2251 |
+
$plaintext = str_split($plaintext, $length);
|
2252 |
+
$ciphertext = '';
|
2253 |
+
foreach ($plaintext as $m) {
|
2254 |
+
$ciphertext.= $this->_rsaes_pkcs1_v1_5_encrypt($m);
|
2255 |
+
}
|
2256 |
+
return $ciphertext;
|
2257 |
+
//case CRYPT_RSA_ENCRYPTION_OAEP:
|
2258 |
+
default:
|
2259 |
+
$length = $this->k - 2 * $this->hLen - 2;
|
2260 |
+
if ($length <= 0) {
|
2261 |
+
return false;
|
2262 |
+
}
|
2263 |
+
|
2264 |
+
$plaintext = str_split($plaintext, $length);
|
2265 |
+
$ciphertext = '';
|
2266 |
+
foreach ($plaintext as $m) {
|
2267 |
+
$ciphertext.= $this->_rsaes_oaep_encrypt($m);
|
2268 |
+
}
|
2269 |
+
return $ciphertext;
|
2270 |
+
}
|
2271 |
+
}
|
2272 |
+
|
2273 |
+
/**
|
2274 |
+
* Decryption
|
2275 |
+
*
|
2276 |
+
* @see encrypt()
|
2277 |
+
* @access public
|
2278 |
+
* @param String $plaintext
|
2279 |
+
* @return String
|
2280 |
+
*/
|
2281 |
+
function decrypt($ciphertext)
|
2282 |
+
{
|
2283 |
+
if ($this->k <= 0) {
|
2284 |
+
return false;
|
2285 |
+
}
|
2286 |
+
|
2287 |
+
$ciphertext = str_split($ciphertext, $this->k);
|
2288 |
+
$plaintext = '';
|
2289 |
+
|
2290 |
+
switch ($this->encryptionMode) {
|
2291 |
+
case CRYPT_RSA_ENCRYPTION_PKCS1:
|
2292 |
+
$decrypt = '_rsaes_pkcs1_v1_5_decrypt';
|
2293 |
+
break;
|
2294 |
+
//case CRYPT_RSA_ENCRYPTION_OAEP:
|
2295 |
+
default:
|
2296 |
+
$decrypt = '_rsaes_oaep_decrypt';
|
2297 |
+
}
|
2298 |
+
|
2299 |
+
foreach ($ciphertext as $c) {
|
2300 |
+
$temp = $this->$decrypt($c);
|
2301 |
+
if ($temp === false) {
|
2302 |
+
return false;
|
2303 |
+
}
|
2304 |
+
$plaintext.= $temp;
|
2305 |
+
}
|
2306 |
+
|
2307 |
+
return $plaintext;
|
2308 |
+
}
|
2309 |
+
|
2310 |
+
/**
|
2311 |
+
* Create a signature
|
2312 |
+
*
|
2313 |
+
* @see verify()
|
2314 |
+
* @access public
|
2315 |
+
* @param String $message
|
2316 |
+
* @return String
|
2317 |
+
*/
|
2318 |
+
function sign($message)
|
2319 |
+
{
|
2320 |
+
if (empty($this->modulus) || empty($this->exponent)) {
|
2321 |
+
return false;
|
2322 |
+
}
|
2323 |
+
|
2324 |
+
switch ($this->signatureMode) {
|
2325 |
+
case CRYPT_RSA_SIGNATURE_PKCS1:
|
2326 |
+
return $this->_rsassa_pkcs1_v1_5_sign($message);
|
2327 |
+
//case CRYPT_RSA_SIGNATURE_PSS:
|
2328 |
+
default:
|
2329 |
+
return $this->_rsassa_pss_sign($message);
|
2330 |
+
}
|
2331 |
+
}
|
2332 |
+
|
2333 |
+
/**
|
2334 |
+
* Verifies a signature
|
2335 |
+
*
|
2336 |
+
* @see sign()
|
2337 |
+
* @access public
|
2338 |
+
* @param String $message
|
2339 |
+
* @param String $signature
|
2340 |
+
* @return Boolean
|
2341 |
+
*/
|
2342 |
+
function verify($message, $signature)
|
2343 |
+
{
|
2344 |
+
if (empty($this->modulus) || empty($this->exponent)) {
|
2345 |
+
return false;
|
2346 |
+
}
|
2347 |
+
|
2348 |
+
switch ($this->signatureMode) {
|
2349 |
+
case CRYPT_RSA_SIGNATURE_PKCS1:
|
2350 |
+
return $this->_rsassa_pkcs1_v1_5_verify($message, $signature);
|
2351 |
+
//case CRYPT_RSA_SIGNATURE_PSS:
|
2352 |
+
default:
|
2353 |
+
return $this->_rsassa_pss_verify($message, $signature);
|
2354 |
+
}
|
2355 |
+
}
|
2356 |
+
}
|
classes/phpseclib/Crypt/Random.php
ADDED
@@ -0,0 +1,133 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Random Number Generator
|
6 |
+
*
|
7 |
+
* PHP versions 4 and 5
|
8 |
+
*
|
9 |
+
* Here's a short example of how to use this library:
|
10 |
+
* <code>
|
11 |
+
* <?php
|
12 |
+
* include('Crypt/Random.php');
|
13 |
+
*
|
14 |
+
* echo crypt_random();
|
15 |
+
* ?>
|
16 |
+
* </code>
|
17 |
+
*
|
18 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
19 |
+
* of this software and associated documentation files (the "Software"), to deal
|
20 |
+
* in the Software without restriction, including without limitation the rights
|
21 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
22 |
+
* copies of the Software, and to permit persons to whom the Software is
|
23 |
+
* furnished to do so, subject to the following conditions:
|
24 |
+
*
|
25 |
+
* The above copyright notice and this permission notice shall be included in
|
26 |
+
* all copies or substantial portions of the Software.
|
27 |
+
*
|
28 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
29 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
30 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
31 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
32 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
33 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
34 |
+
* THE SOFTWARE.
|
35 |
+
*
|
36 |
+
* @category Crypt
|
37 |
+
* @package Crypt_Random
|
38 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
39 |
+
* @copyright MMVII Jim Wigginton
|
40 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
41 |
+
* @version $Id: Random.php,v 1.9 2010/04/24 06:40:48 terrafrost Exp $
|
42 |
+
* @link http://phpseclib.sourceforge.net
|
43 |
+
*/
|
44 |
+
|
45 |
+
/**
|
46 |
+
* Generate a random value.
|
47 |
+
*
|
48 |
+
* On 32-bit machines, the largest distance that can exist between $min and $max is 2**31.
|
49 |
+
* If $min and $max are farther apart than that then the last ($max - range) numbers.
|
50 |
+
*
|
51 |
+
* Depending on how this is being used, it may be worth while to write a replacement. For example,
|
52 |
+
* a PHP-based web app that stores its data in an SQL database can collect more entropy than this function
|
53 |
+
* can.
|
54 |
+
*
|
55 |
+
* @param optional Integer $min
|
56 |
+
* @param optional Integer $max
|
57 |
+
* @return Integer
|
58 |
+
* @access public
|
59 |
+
*/
|
60 |
+
function crypt_random($min = 0, $max = 0x7FFFFFFF)
|
61 |
+
{
|
62 |
+
if ($min == $max) {
|
63 |
+
return $min;
|
64 |
+
}
|
65 |
+
|
66 |
+
// see http://en.wikipedia.org/wiki//dev/random
|
67 |
+
static $urandom = true;
|
68 |
+
if ($urandom === true) {
|
69 |
+
// Warning's will be output unles the error suppression operator is used. Errors such as
|
70 |
+
// "open_basedir restriction in effect", "Permission denied", "No such file or directory", etc.
|
71 |
+
$urandom = @fopen('/dev/urandom', 'rb');
|
72 |
+
}
|
73 |
+
if (!is_bool($urandom)) {
|
74 |
+
extract(unpack('Nrandom', fread($urandom, 4)));
|
75 |
+
|
76 |
+
// say $min = 0 and $max = 3. if we didn't do abs() then we could have stuff like this:
|
77 |
+
// -4 % 3 + 0 = -1, even though -1 < $min
|
78 |
+
return abs($random) % ($max - $min) + $min;
|
79 |
+
}
|
80 |
+
|
81 |
+
/* Prior to PHP 4.2.0, mt_srand() had to be called before mt_rand() could be called.
|
82 |
+
Prior to PHP 5.2.6, mt_rand()'s automatic seeding was subpar, as elaborated here:
|
83 |
+
|
84 |
+
http://www.suspekt.org/2008/08/17/mt_srand-and-not-so-random-numbers/
|
85 |
+
|
86 |
+
The seeding routine is pretty much ripped from PHP's own internal GENERATE_SEED() macro:
|
87 |
+
|
88 |
+
http://svn.php.net/viewvc/php/php-src/branches/PHP_5_3_2/ext/standard/php_rand.h?view=markup */
|
89 |
+
if (version_compare(PHP_VERSION, '5.2.5', '<=')) {
|
90 |
+
static $seeded;
|
91 |
+
if (!isset($seeded)) {
|
92 |
+
$seeded = true;
|
93 |
+
mt_srand(fmod(time() * getmypid(), 0x7FFFFFFF) ^ fmod(1000000 * lcg_value(), 0x7FFFFFFF));
|
94 |
+
}
|
95 |
+
}
|
96 |
+
|
97 |
+
static $crypto;
|
98 |
+
|
99 |
+
// The CSPRNG's Yarrow and Fortuna periodically reseed. This function can be reseeded by hitting F5
|
100 |
+
// in the browser and reloading the page.
|
101 |
+
|
102 |
+
if (!isset($crypto)) {
|
103 |
+
$key = $iv = '';
|
104 |
+
for ($i = 0; $i < 8; $i++) {
|
105 |
+
$key.= pack('n', mt_rand(0, 0xFFFF));
|
106 |
+
$iv .= pack('n', mt_rand(0, 0xFFFF));
|
107 |
+
}
|
108 |
+
switch (true) {
|
109 |
+
case class_exists('Crypt_AES'):
|
110 |
+
$crypto = new Crypt_AES(CRYPT_AES_MODE_CTR);
|
111 |
+
break;
|
112 |
+
case class_exists('Crypt_TripleDES'):
|
113 |
+
$crypto = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
|
114 |
+
break;
|
115 |
+
case class_exists('Crypt_DES'):
|
116 |
+
$crypto = new Crypt_DES(CRYPT_DES_MODE_CTR);
|
117 |
+
break;
|
118 |
+
case class_exists('Crypt_RC4'):
|
119 |
+
$crypto = new Crypt_RC4();
|
120 |
+
break;
|
121 |
+
default:
|
122 |
+
extract(unpack('Nrandom', pack('H*', sha1(mt_rand(0, 0x7FFFFFFF)))));
|
123 |
+
return abs($random) % ($max - $min) + $min;
|
124 |
+
}
|
125 |
+
$crypto->setKey($key);
|
126 |
+
$crypto->setIV($iv);
|
127 |
+
$crypto->enableContinuousBuffer();
|
128 |
+
}
|
129 |
+
|
130 |
+
extract(unpack('Nrandom', $crypto->encrypt("\0\0\0\0")));
|
131 |
+
return abs($random) % ($max - $min) + $min;
|
132 |
+
}
|
133 |
+
?>
|
classes/phpseclib/Crypt/Rijndael.php
ADDED
@@ -0,0 +1,1424 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of Rijndael.
|
6 |
+
*
|
7 |
+
* Does not use mcrypt, even when available, for reasons that are explained below.
|
8 |
+
*
|
9 |
+
* PHP versions 4 and 5
|
10 |
+
*
|
11 |
+
* If {@link Crypt_Rijndael::setBlockLength() setBlockLength()} isn't called, it'll be assumed to be 128 bits. If
|
12 |
+
* {@link Crypt_Rijndael::setKeyLength() setKeyLength()} isn't called, it'll be calculated from
|
13 |
+
* {@link Crypt_Rijndael::setKey() setKey()}. ie. if the key is 128-bits, the key length will be 128-bits. If it's
|
14 |
+
* 136-bits it'll be null-padded to 160-bits and 160 bits will be the key length until
|
15 |
+
* {@link Crypt_Rijndael::setKey() setKey()} is called, again, at which point, it'll be recalculated.
|
16 |
+
*
|
17 |
+
* Not all Rijndael implementations may support 160-bits or 224-bits as the block length / key length. mcrypt, for example,
|
18 |
+
* does not. AES, itself, only supports block lengths of 128 and key lengths of 128, 192, and 256.
|
19 |
+
* {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=10 Rijndael-ammended.pdf#page=10} defines the
|
20 |
+
* algorithm for block lengths of 192 and 256 but not for block lengths / key lengths of 160 and 224. Indeed, 160 and 224
|
21 |
+
* are first defined as valid key / block lengths in
|
22 |
+
* {@link http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=44 Rijndael-ammended.pdf#page=44}:
|
23 |
+
* Extensions: Other block and Cipher Key lengths.
|
24 |
+
*
|
25 |
+
* {@internal The variable names are the same as those in
|
26 |
+
* {@link http://www.csrc.nist.gov/publications/fips/fips197/fips-197.pdf#page=10 fips-197.pdf#page=10}.}}
|
27 |
+
*
|
28 |
+
* Here's a short example of how to use this library:
|
29 |
+
* <code>
|
30 |
+
* <?php
|
31 |
+
* include('Crypt/Rijndael.php');
|
32 |
+
*
|
33 |
+
* $rijndael = new Crypt_Rijndael();
|
34 |
+
*
|
35 |
+
* $rijndael->setKey('abcdefghijklmnop');
|
36 |
+
*
|
37 |
+
* $size = 10 * 1024;
|
38 |
+
* $plaintext = '';
|
39 |
+
* for ($i = 0; $i < $size; $i++) {
|
40 |
+
* $plaintext.= 'a';
|
41 |
+
* }
|
42 |
+
*
|
43 |
+
* echo $rijndael->decrypt($rijndael->encrypt($plaintext));
|
44 |
+
* ?>
|
45 |
+
* </code>
|
46 |
+
*
|
47 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
48 |
+
* of this software and associated documentation files (the "Software"), to deal
|
49 |
+
* in the Software without restriction, including without limitation the rights
|
50 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
51 |
+
* copies of the Software, and to permit persons to whom the Software is
|
52 |
+
* furnished to do so, subject to the following conditions:
|
53 |
+
*
|
54 |
+
* The above copyright notice and this permission notice shall be included in
|
55 |
+
* all copies or substantial portions of the Software.
|
56 |
+
*
|
57 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
58 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
59 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
60 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
61 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
62 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
63 |
+
* THE SOFTWARE.
|
64 |
+
*
|
65 |
+
* @category Crypt
|
66 |
+
* @package Crypt_Rijndael
|
67 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
68 |
+
* @copyright MMVIII Jim Wigginton
|
69 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
70 |
+
* @version $Id: Rijndael.php,v 1.12 2010/02/09 06:10:26 terrafrost Exp $
|
71 |
+
* @link http://phpseclib.sourceforge.net
|
72 |
+
*/
|
73 |
+
|
74 |
+
/**#@+
|
75 |
+
* @access public
|
76 |
+
* @see Crypt_Rijndael::encrypt()
|
77 |
+
* @see Crypt_Rijndael::decrypt()
|
78 |
+
*/
|
79 |
+
/**
|
80 |
+
* Encrypt / decrypt using the Counter mode.
|
81 |
+
*
|
82 |
+
* Set to -1 since that's what Crypt/Random.php uses to index the CTR mode.
|
83 |
+
*
|
84 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Counter_.28CTR.29
|
85 |
+
*/
|
86 |
+
define('CRYPT_RIJNDAEL_MODE_CTR', -1);
|
87 |
+
/**
|
88 |
+
* Encrypt / decrypt using the Electronic Code Book mode.
|
89 |
+
*
|
90 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Electronic_codebook_.28ECB.29
|
91 |
+
*/
|
92 |
+
define('CRYPT_RIJNDAEL_MODE_ECB', 1);
|
93 |
+
/**
|
94 |
+
* Encrypt / decrypt using the Code Book Chaining mode.
|
95 |
+
*
|
96 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher-block_chaining_.28CBC.29
|
97 |
+
*/
|
98 |
+
define('CRYPT_RIJNDAEL_MODE_CBC', 2);
|
99 |
+
/**
|
100 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
101 |
+
*
|
102 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Cipher_feedback_.28CFB.29
|
103 |
+
*/
|
104 |
+
define('CRYPT_RIJNDAEL_MODE_CFB', 3);
|
105 |
+
/**
|
106 |
+
* Encrypt / decrypt using the Cipher Feedback mode.
|
107 |
+
*
|
108 |
+
* @link http://en.wikipedia.org/wiki/Block_cipher_modes_of_operation#Output_feedback_.28OFB.29
|
109 |
+
*/
|
110 |
+
define('CRYPT_RIJNDAEL_MODE_OFB', 4);
|
111 |
+
/**#@-*/
|
112 |
+
|
113 |
+
/**#@+
|
114 |
+
* @access private
|
115 |
+
* @see Crypt_Rijndael::Crypt_Rijndael()
|
116 |
+
*/
|
117 |
+
/**
|
118 |
+
* Toggles the internal implementation
|
119 |
+
*/
|
120 |
+
define('CRYPT_RIJNDAEL_MODE_INTERNAL', 1);
|
121 |
+
/**
|
122 |
+
* Toggles the mcrypt implementation
|
123 |
+
*/
|
124 |
+
define('CRYPT_RIJNDAEL_MODE_MCRYPT', 2);
|
125 |
+
/**#@-*/
|
126 |
+
|
127 |
+
/**
|
128 |
+
* Pure-PHP implementation of Rijndael.
|
129 |
+
*
|
130 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
131 |
+
* @version 0.1.0
|
132 |
+
* @access public
|
133 |
+
* @package Crypt_Rijndael
|
134 |
+
*/
|
135 |
+
class Crypt_Rijndael {
|
136 |
+
/**
|
137 |
+
* The Encryption Mode
|
138 |
+
*
|
139 |
+
* @see Crypt_Rijndael::Crypt_Rijndael()
|
140 |
+
* @var Integer
|
141 |
+
* @access private
|
142 |
+
*/
|
143 |
+
var $mode;
|
144 |
+
|
145 |
+
/**
|
146 |
+
* The Key
|
147 |
+
*
|
148 |
+
* @see Crypt_Rijndael::setKey()
|
149 |
+
* @var String
|
150 |
+
* @access private
|
151 |
+
*/
|
152 |
+
var $key = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
|
153 |
+
|
154 |
+
/**
|
155 |
+
* The Initialization Vector
|
156 |
+
*
|
157 |
+
* @see Crypt_Rijndael::setIV()
|
158 |
+
* @var String
|
159 |
+
* @access private
|
160 |
+
*/
|
161 |
+
var $iv = '';
|
162 |
+
|
163 |
+
/**
|
164 |
+
* A "sliding" Initialization Vector
|
165 |
+
*
|
166 |
+
* @see Crypt_Rijndael::enableContinuousBuffer()
|
167 |
+
* @var String
|
168 |
+
* @access private
|
169 |
+
*/
|
170 |
+
var $encryptIV = '';
|
171 |
+
|
172 |
+
/**
|
173 |
+
* A "sliding" Initialization Vector
|
174 |
+
*
|
175 |
+
* @see Crypt_Rijndael::enableContinuousBuffer()
|
176 |
+
* @var String
|
177 |
+
* @access private
|
178 |
+
*/
|
179 |
+
var $decryptIV = '';
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Continuous Buffer status
|
183 |
+
*
|
184 |
+
* @see Crypt_Rijndael::enableContinuousBuffer()
|
185 |
+
* @var Boolean
|
186 |
+
* @access private
|
187 |
+
*/
|
188 |
+
var $continuousBuffer = false;
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Padding status
|
192 |
+
*
|
193 |
+
* @see Crypt_Rijndael::enablePadding()
|
194 |
+
* @var Boolean
|
195 |
+
* @access private
|
196 |
+
*/
|
197 |
+
var $padding = true;
|
198 |
+
|
199 |
+
/**
|
200 |
+
* Does the key schedule need to be (re)calculated?
|
201 |
+
*
|
202 |
+
* @see setKey()
|
203 |
+
* @see setBlockLength()
|
204 |
+
* @see setKeyLength()
|
205 |
+
* @var Boolean
|
206 |
+
* @access private
|
207 |
+
*/
|
208 |
+
var $changed = true;
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Has the key length explicitly been set or should it be derived from the key, itself?
|
212 |
+
*
|
213 |
+
* @see setKeyLength()
|
214 |
+
* @var Boolean
|
215 |
+
* @access private
|
216 |
+
*/
|
217 |
+
var $explicit_key_length = false;
|
218 |
+
|
219 |
+
/**
|
220 |
+
* The Key Schedule
|
221 |
+
*
|
222 |
+
* @see _setup()
|
223 |
+
* @var Array
|
224 |
+
* @access private
|
225 |
+
*/
|
226 |
+
var $w;
|
227 |
+
|
228 |
+
/**
|
229 |
+
* The Inverse Key Schedule
|
230 |
+
*
|
231 |
+
* @see _setup()
|
232 |
+
* @var Array
|
233 |
+
* @access private
|
234 |
+
*/
|
235 |
+
var $dw;
|
236 |
+
|
237 |
+
/**
|
238 |
+
* The Block Length
|
239 |
+
*
|
240 |
+
* @see setBlockLength()
|
241 |
+
* @var Integer
|
242 |
+
* @access private
|
243 |
+
* @internal The max value is 32, the min value is 16. All valid values are multiples of 4. Exists in conjunction with
|
244 |
+
* $Nb because we need this value and not $Nb to pad strings appropriately.
|
245 |
+
*/
|
246 |
+
var $block_size = 16;
|
247 |
+
|
248 |
+
/**
|
249 |
+
* The Block Length divided by 32
|
250 |
+
*
|
251 |
+
* @see setBlockLength()
|
252 |
+
* @var Integer
|
253 |
+
* @access private
|
254 |
+
* @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4. Exists in conjunction with $block_size
|
255 |
+
* because the encryption / decryption / key schedule creation requires this number and not $block_size. We could
|
256 |
+
* derive this from $block_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
|
257 |
+
* of that, we'll just precompute it once.
|
258 |
+
*
|
259 |
+
*/
|
260 |
+
var $Nb = 4;
|
261 |
+
|
262 |
+
/**
|
263 |
+
* The Key Length
|
264 |
+
*
|
265 |
+
* @see setKeyLength()
|
266 |
+
* @var Integer
|
267 |
+
* @access private
|
268 |
+
* @internal The max value is 256 / 8 = 32, the min value is 128 / 8 = 16. Exists in conjunction with $key_size
|
269 |
+
* because the encryption / decryption / key schedule creation requires this number and not $key_size. We could
|
270 |
+
* derive this from $key_size or vice versa, but that'd mean we'd have to do multiple shift operations, so in lieu
|
271 |
+
* of that, we'll just precompute it once.
|
272 |
+
*/
|
273 |
+
var $key_size = 16;
|
274 |
+
|
275 |
+
/**
|
276 |
+
* The Key Length divided by 32
|
277 |
+
*
|
278 |
+
* @see setKeyLength()
|
279 |
+
* @var Integer
|
280 |
+
* @access private
|
281 |
+
* @internal The max value is 256 / 32 = 8, the min value is 128 / 32 = 4
|
282 |
+
*/
|
283 |
+
var $Nk = 4;
|
284 |
+
|
285 |
+
/**
|
286 |
+
* The Number of Rounds
|
287 |
+
*
|
288 |
+
* @var Integer
|
289 |
+
* @access private
|
290 |
+
* @internal The max value is 14, the min value is 10.
|
291 |
+
*/
|
292 |
+
var $Nr;
|
293 |
+
|
294 |
+
/**
|
295 |
+
* Shift offsets
|
296 |
+
*
|
297 |
+
* @var Array
|
298 |
+
* @access private
|
299 |
+
*/
|
300 |
+
var $c;
|
301 |
+
|
302 |
+
/**
|
303 |
+
* Precomputed mixColumns table
|
304 |
+
*
|
305 |
+
* @see Crypt_Rijndael()
|
306 |
+
* @var Array
|
307 |
+
* @access private
|
308 |
+
*/
|
309 |
+
var $t0;
|
310 |
+
|
311 |
+
/**
|
312 |
+
* Precomputed mixColumns table
|
313 |
+
*
|
314 |
+
* @see Crypt_Rijndael()
|
315 |
+
* @var Array
|
316 |
+
* @access private
|
317 |
+
*/
|
318 |
+
var $t1;
|
319 |
+
|
320 |
+
/**
|
321 |
+
* Precomputed mixColumns table
|
322 |
+
*
|
323 |
+
* @see Crypt_Rijndael()
|
324 |
+
* @var Array
|
325 |
+
* @access private
|
326 |
+
*/
|
327 |
+
var $t2;
|
328 |
+
|
329 |
+
/**
|
330 |
+
* Precomputed mixColumns table
|
331 |
+
*
|
332 |
+
* @see Crypt_Rijndael()
|
333 |
+
* @var Array
|
334 |
+
* @access private
|
335 |
+
*/
|
336 |
+
var $t3;
|
337 |
+
|
338 |
+
/**
|
339 |
+
* Precomputed invMixColumns table
|
340 |
+
*
|
341 |
+
* @see Crypt_Rijndael()
|
342 |
+
* @var Array
|
343 |
+
* @access private
|
344 |
+
*/
|
345 |
+
var $dt0;
|
346 |
+
|
347 |
+
/**
|
348 |
+
* Precomputed invMixColumns table
|
349 |
+
*
|
350 |
+
* @see Crypt_Rijndael()
|
351 |
+
* @var Array
|
352 |
+
* @access private
|
353 |
+
*/
|
354 |
+
var $dt1;
|
355 |
+
|
356 |
+
/**
|
357 |
+
* Precomputed invMixColumns table
|
358 |
+
*
|
359 |
+
* @see Crypt_Rijndael()
|
360 |
+
* @var Array
|
361 |
+
* @access private
|
362 |
+
*/
|
363 |
+
var $dt2;
|
364 |
+
|
365 |
+
/**
|
366 |
+
* Precomputed invMixColumns table
|
367 |
+
*
|
368 |
+
* @see Crypt_Rijndael()
|
369 |
+
* @var Array
|
370 |
+
* @access private
|
371 |
+
*/
|
372 |
+
var $dt3;
|
373 |
+
|
374 |
+
/**
|
375 |
+
* Is the mode one that is paddable?
|
376 |
+
*
|
377 |
+
* @see Crypt_Rijndael::Crypt_Rijndael()
|
378 |
+
* @var Boolean
|
379 |
+
* @access private
|
380 |
+
*/
|
381 |
+
var $paddable = false;
|
382 |
+
|
383 |
+
/**
|
384 |
+
* Encryption buffer for CTR, OFB and CFB modes
|
385 |
+
*
|
386 |
+
* @see Crypt_Rijndael::encrypt()
|
387 |
+
* @var String
|
388 |
+
* @access private
|
389 |
+
*/
|
390 |
+
var $enbuffer = array('encrypted' => '', 'xor' => '');
|
391 |
+
|
392 |
+
/**
|
393 |
+
* Decryption buffer for CTR, OFB and CFB modes
|
394 |
+
*
|
395 |
+
* @see Crypt_Rijndael::decrypt()
|
396 |
+
* @var String
|
397 |
+
* @access private
|
398 |
+
*/
|
399 |
+
var $debuffer = array('ciphertext' => '');
|
400 |
+
|
401 |
+
/**
|
402 |
+
* Default Constructor.
|
403 |
+
*
|
404 |
+
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
|
405 |
+
* CRYPT_RIJNDAEL_MODE_ECB or CRYPT_RIJNDAEL_MODE_CBC. If not explictly set, CRYPT_RIJNDAEL_MODE_CBC will be used.
|
406 |
+
*
|
407 |
+
* @param optional Integer $mode
|
408 |
+
* @return Crypt_Rijndael
|
409 |
+
* @access public
|
410 |
+
*/
|
411 |
+
function Crypt_Rijndael($mode = CRYPT_RIJNDAEL_MODE_CBC)
|
412 |
+
{
|
413 |
+
switch ($mode) {
|
414 |
+
case CRYPT_RIJNDAEL_MODE_ECB:
|
415 |
+
case CRYPT_RIJNDAEL_MODE_CBC:
|
416 |
+
$this->paddable = true;
|
417 |
+
$this->mode = $mode;
|
418 |
+
break;
|
419 |
+
case CRYPT_RIJNDAEL_MODE_CTR:
|
420 |
+
case CRYPT_RIJNDAEL_MODE_CFB:
|
421 |
+
case CRYPT_RIJNDAEL_MODE_OFB:
|
422 |
+
$this->mode = $mode;
|
423 |
+
break;
|
424 |
+
default:
|
425 |
+
$this->paddable = true;
|
426 |
+
$this->mode = CRYPT_RIJNDAEL_MODE_CBC;
|
427 |
+
}
|
428 |
+
|
429 |
+
$t3 = &$this->t3;
|
430 |
+
$t2 = &$this->t2;
|
431 |
+
$t1 = &$this->t1;
|
432 |
+
$t0 = &$this->t0;
|
433 |
+
|
434 |
+
$dt3 = &$this->dt3;
|
435 |
+
$dt2 = &$this->dt2;
|
436 |
+
$dt1 = &$this->dt1;
|
437 |
+
$dt0 = &$this->dt0;
|
438 |
+
|
439 |
+
// according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=19> (section 5.2.1),
|
440 |
+
// precomputed tables can be used in the mixColumns phase. in that example, they're assigned t0...t3, so
|
441 |
+
// those are the names we'll use.
|
442 |
+
$t3 = array(
|
443 |
+
0x6363A5C6, 0x7C7C84F8, 0x777799EE, 0x7B7B8DF6, 0xF2F20DFF, 0x6B6BBDD6, 0x6F6FB1DE, 0xC5C55491,
|
444 |
+
0x30305060, 0x01010302, 0x6767A9CE, 0x2B2B7D56, 0xFEFE19E7, 0xD7D762B5, 0xABABE64D, 0x76769AEC,
|
445 |
+
0xCACA458F, 0x82829D1F, 0xC9C94089, 0x7D7D87FA, 0xFAFA15EF, 0x5959EBB2, 0x4747C98E, 0xF0F00BFB,
|
446 |
+
0xADADEC41, 0xD4D467B3, 0xA2A2FD5F, 0xAFAFEA45, 0x9C9CBF23, 0xA4A4F753, 0x727296E4, 0xC0C05B9B,
|
447 |
+
0xB7B7C275, 0xFDFD1CE1, 0x9393AE3D, 0x26266A4C, 0x36365A6C, 0x3F3F417E, 0xF7F702F5, 0xCCCC4F83,
|
448 |
+
0x34345C68, 0xA5A5F451, 0xE5E534D1, 0xF1F108F9, 0x717193E2, 0xD8D873AB, 0x31315362, 0x15153F2A,
|
449 |
+
0x04040C08, 0xC7C75295, 0x23236546, 0xC3C35E9D, 0x18182830, 0x9696A137, 0x05050F0A, 0x9A9AB52F,
|
450 |
+
0x0707090E, 0x12123624, 0x80809B1B, 0xE2E23DDF, 0xEBEB26CD, 0x2727694E, 0xB2B2CD7F, 0x75759FEA,
|
451 |
+
0x09091B12, 0x83839E1D, 0x2C2C7458, 0x1A1A2E34, 0x1B1B2D36, 0x6E6EB2DC, 0x5A5AEEB4, 0xA0A0FB5B,
|
452 |
+
0x5252F6A4, 0x3B3B4D76, 0xD6D661B7, 0xB3B3CE7D, 0x29297B52, 0xE3E33EDD, 0x2F2F715E, 0x84849713,
|
453 |
+
0x5353F5A6, 0xD1D168B9, 0x00000000, 0xEDED2CC1, 0x20206040, 0xFCFC1FE3, 0xB1B1C879, 0x5B5BEDB6,
|
454 |
+
0x6A6ABED4, 0xCBCB468D, 0xBEBED967, 0x39394B72, 0x4A4ADE94, 0x4C4CD498, 0x5858E8B0, 0xCFCF4A85,
|
455 |
+
0xD0D06BBB, 0xEFEF2AC5, 0xAAAAE54F, 0xFBFB16ED, 0x4343C586, 0x4D4DD79A, 0x33335566, 0x85859411,
|
456 |
+
0x4545CF8A, 0xF9F910E9, 0x02020604, 0x7F7F81FE, 0x5050F0A0, 0x3C3C4478, 0x9F9FBA25, 0xA8A8E34B,
|
457 |
+
0x5151F3A2, 0xA3A3FE5D, 0x4040C080, 0x8F8F8A05, 0x9292AD3F, 0x9D9DBC21, 0x38384870, 0xF5F504F1,
|
458 |
+
0xBCBCDF63, 0xB6B6C177, 0xDADA75AF, 0x21216342, 0x10103020, 0xFFFF1AE5, 0xF3F30EFD, 0xD2D26DBF,
|
459 |
+
0xCDCD4C81, 0x0C0C1418, 0x13133526, 0xECEC2FC3, 0x5F5FE1BE, 0x9797A235, 0x4444CC88, 0x1717392E,
|
460 |
+
0xC4C45793, 0xA7A7F255, 0x7E7E82FC, 0x3D3D477A, 0x6464ACC8, 0x5D5DE7BA, 0x19192B32, 0x737395E6,
|
461 |
+
0x6060A0C0, 0x81819819, 0x4F4FD19E, 0xDCDC7FA3, 0x22226644, 0x2A2A7E54, 0x9090AB3B, 0x8888830B,
|
462 |
+
0x4646CA8C, 0xEEEE29C7, 0xB8B8D36B, 0x14143C28, 0xDEDE79A7, 0x5E5EE2BC, 0x0B0B1D16, 0xDBDB76AD,
|
463 |
+
0xE0E03BDB, 0x32325664, 0x3A3A4E74, 0x0A0A1E14, 0x4949DB92, 0x06060A0C, 0x24246C48, 0x5C5CE4B8,
|
464 |
+
0xC2C25D9F, 0xD3D36EBD, 0xACACEF43, 0x6262A6C4, 0x9191A839, 0x9595A431, 0xE4E437D3, 0x79798BF2,
|
465 |
+
0xE7E732D5, 0xC8C8438B, 0x3737596E, 0x6D6DB7DA, 0x8D8D8C01, 0xD5D564B1, 0x4E4ED29C, 0xA9A9E049,
|
466 |
+
0x6C6CB4D8, 0x5656FAAC, 0xF4F407F3, 0xEAEA25CF, 0x6565AFCA, 0x7A7A8EF4, 0xAEAEE947, 0x08081810,
|
467 |
+
0xBABAD56F, 0x787888F0, 0x25256F4A, 0x2E2E725C, 0x1C1C2438, 0xA6A6F157, 0xB4B4C773, 0xC6C65197,
|
468 |
+
0xE8E823CB, 0xDDDD7CA1, 0x74749CE8, 0x1F1F213E, 0x4B4BDD96, 0xBDBDDC61, 0x8B8B860D, 0x8A8A850F,
|
469 |
+
0x707090E0, 0x3E3E427C, 0xB5B5C471, 0x6666AACC, 0x4848D890, 0x03030506, 0xF6F601F7, 0x0E0E121C,
|
470 |
+
0x6161A3C2, 0x35355F6A, 0x5757F9AE, 0xB9B9D069, 0x86869117, 0xC1C15899, 0x1D1D273A, 0x9E9EB927,
|
471 |
+
0xE1E138D9, 0xF8F813EB, 0x9898B32B, 0x11113322, 0x6969BBD2, 0xD9D970A9, 0x8E8E8907, 0x9494A733,
|
472 |
+
0x9B9BB62D, 0x1E1E223C, 0x87879215, 0xE9E920C9, 0xCECE4987, 0x5555FFAA, 0x28287850, 0xDFDF7AA5,
|
473 |
+
0x8C8C8F03, 0xA1A1F859, 0x89898009, 0x0D0D171A, 0xBFBFDA65, 0xE6E631D7, 0x4242C684, 0x6868B8D0,
|
474 |
+
0x4141C382, 0x9999B029, 0x2D2D775A, 0x0F0F111E, 0xB0B0CB7B, 0x5454FCA8, 0xBBBBD66D, 0x16163A2C
|
475 |
+
);
|
476 |
+
|
477 |
+
$dt3 = array(
|
478 |
+
0xF4A75051, 0x4165537E, 0x17A4C31A, 0x275E963A, 0xAB6BCB3B, 0x9D45F11F, 0xFA58ABAC, 0xE303934B,
|
479 |
+
0x30FA5520, 0x766DF6AD, 0xCC769188, 0x024C25F5, 0xE5D7FC4F, 0x2ACBD7C5, 0x35448026, 0x62A38FB5,
|
480 |
+
0xB15A49DE, 0xBA1B6725, 0xEA0E9845, 0xFEC0E15D, 0x2F7502C3, 0x4CF01281, 0x4697A38D, 0xD3F9C66B,
|
481 |
+
0x8F5FE703, 0x929C9515, 0x6D7AEBBF, 0x5259DA95, 0xBE832DD4, 0x7421D358, 0xE0692949, 0xC9C8448E,
|
482 |
+
0xC2896A75, 0x8E7978F4, 0x583E6B99, 0xB971DD27, 0xE14FB6BE, 0x88AD17F0, 0x20AC66C9, 0xCE3AB47D,
|
483 |
+
0xDF4A1863, 0x1A3182E5, 0x51336097, 0x537F4562, 0x6477E0B1, 0x6BAE84BB, 0x81A01CFE, 0x082B94F9,
|
484 |
+
0x48685870, 0x45FD198F, 0xDE6C8794, 0x7BF8B752, 0x73D323AB, 0x4B02E272, 0x1F8F57E3, 0x55AB2A66,
|
485 |
+
0xEB2807B2, 0xB5C2032F, 0xC57B9A86, 0x3708A5D3, 0x2887F230, 0xBFA5B223, 0x036ABA02, 0x16825CED,
|
486 |
+
0xCF1C2B8A, 0x79B492A7, 0x07F2F0F3, 0x69E2A14E, 0xDAF4CD65, 0x05BED506, 0x34621FD1, 0xA6FE8AC4,
|
487 |
+
0x2E539D34, 0xF355A0A2, 0x8AE13205, 0xF6EB75A4, 0x83EC390B, 0x60EFAA40, 0x719F065E, 0x6E1051BD,
|
488 |
+
0x218AF93E, 0xDD063D96, 0x3E05AEDD, 0xE6BD464D, 0x548DB591, 0xC45D0571, 0x06D46F04, 0x5015FF60,
|
489 |
+
0x98FB2419, 0xBDE997D6, 0x4043CC89, 0xD99E7767, 0xE842BDB0, 0x898B8807, 0x195B38E7, 0xC8EEDB79,
|
490 |
+
0x7C0A47A1, 0x420FE97C, 0x841EC9F8, 0x00000000, 0x80868309, 0x2BED4832, 0x1170AC1E, 0x5A724E6C,
|
491 |
+
0x0EFFFBFD, 0x8538560F, 0xAED51E3D, 0x2D392736, 0x0FD9640A, 0x5CA62168, 0x5B54D19B, 0x362E3A24,
|
492 |
+
0x0A67B10C, 0x57E70F93, 0xEE96D2B4, 0x9B919E1B, 0xC0C54F80, 0xDC20A261, 0x774B695A, 0x121A161C,
|
493 |
+
0x93BA0AE2, 0xA02AE5C0, 0x22E0433C, 0x1B171D12, 0x090D0B0E, 0x8BC7ADF2, 0xB6A8B92D, 0x1EA9C814,
|
494 |
+
0xF1198557, 0x75074CAF, 0x99DDBBEE, 0x7F60FDA3, 0x01269FF7, 0x72F5BC5C, 0x663BC544, 0xFB7E345B,
|
495 |
+
0x4329768B, 0x23C6DCCB, 0xEDFC68B6, 0xE4F163B8, 0x31DCCAD7, 0x63851042, 0x97224013, 0xC6112084,
|
496 |
+
0x4A247D85, 0xBB3DF8D2, 0xF93211AE, 0x29A16DC7, 0x9E2F4B1D, 0xB230F3DC, 0x8652EC0D, 0xC1E3D077,
|
497 |
+
0xB3166C2B, 0x70B999A9, 0x9448FA11, 0xE9642247, 0xFC8CC4A8, 0xF03F1AA0, 0x7D2CD856, 0x3390EF22,
|
498 |
+
0x494EC787, 0x38D1C1D9, 0xCAA2FE8C, 0xD40B3698, 0xF581CFA6, 0x7ADE28A5, 0xB78E26DA, 0xADBFA43F,
|
499 |
+
0x3A9DE42C, 0x78920D50, 0x5FCC9B6A, 0x7E466254, 0x8D13C2F6, 0xD8B8E890, 0x39F75E2E, 0xC3AFF582,
|
500 |
+
0x5D80BE9F, 0xD0937C69, 0xD52DA96F, 0x2512B3CF, 0xAC993BC8, 0x187DA710, 0x9C636EE8, 0x3BBB7BDB,
|
501 |
+
0x267809CD, 0x5918F46E, 0x9AB701EC, 0x4F9AA883, 0x956E65E6, 0xFFE67EAA, 0xBCCF0821, 0x15E8E6EF,
|
502 |
+
0xE79BD9BA, 0x6F36CE4A, 0x9F09D4EA, 0xB07CD629, 0xA4B2AF31, 0x3F23312A, 0xA59430C6, 0xA266C035,
|
503 |
+
0x4EBC3774, 0x82CAA6FC, 0x90D0B0E0, 0xA7D81533, 0x04984AF1, 0xECDAF741, 0xCD500E7F, 0x91F62F17,
|
504 |
+
0x4DD68D76, 0xEFB04D43, 0xAA4D54CC, 0x9604DFE4, 0xD1B5E39E, 0x6A881B4C, 0x2C1FB8C1, 0x65517F46,
|
505 |
+
0x5EEA049D, 0x8C355D01, 0x877473FA, 0x0B412EFB, 0x671D5AB3, 0xDBD25292, 0x105633E9, 0xD647136D,
|
506 |
+
0xD7618C9A, 0xA10C7A37, 0xF8148E59, 0x133C89EB, 0xA927EECE, 0x61C935B7, 0x1CE5EDE1, 0x47B13C7A,
|
507 |
+
0xD2DF599C, 0xF2733F55, 0x14CE7918, 0xC737BF73, 0xF7CDEA53, 0xFDAA5B5F, 0x3D6F14DF, 0x44DB8678,
|
508 |
+
0xAFF381CA, 0x68C43EB9, 0x24342C38, 0xA3405FC2, 0x1DC37216, 0xE2250CBC, 0x3C498B28, 0x0D9541FF,
|
509 |
+
0xA8017139, 0x0CB3DE08, 0xB4E49CD8, 0x56C19064, 0xCB84617B, 0x32B670D5, 0x6C5C7448, 0xB85742D0
|
510 |
+
);
|
511 |
+
|
512 |
+
for ($i = 0; $i < 256; $i++) {
|
513 |
+
$t2[$i << 8] = (($t3[$i] << 8) & 0xFFFFFF00) | (($t3[$i] >> 24) & 0x000000FF);
|
514 |
+
$t1[$i << 16] = (($t3[$i] << 16) & 0xFFFF0000) | (($t3[$i] >> 16) & 0x0000FFFF);
|
515 |
+
$t0[$i << 24] = (($t3[$i] << 24) & 0xFF000000) | (($t3[$i] >> 8) & 0x00FFFFFF);
|
516 |
+
|
517 |
+
$dt2[$i << 8] = (($this->dt3[$i] << 8) & 0xFFFFFF00) | (($dt3[$i] >> 24) & 0x000000FF);
|
518 |
+
$dt1[$i << 16] = (($this->dt3[$i] << 16) & 0xFFFF0000) | (($dt3[$i] >> 16) & 0x0000FFFF);
|
519 |
+
$dt0[$i << 24] = (($this->dt3[$i] << 24) & 0xFF000000) | (($dt3[$i] >> 8) & 0x00FFFFFF);
|
520 |
+
}
|
521 |
+
}
|
522 |
+
|
523 |
+
/**
|
524 |
+
* Sets the key.
|
525 |
+
*
|
526 |
+
* Keys can be of any length. Rijndael, itself, requires the use of a key that's between 128-bits and 256-bits long and
|
527 |
+
* whose length is a multiple of 32. If the key is less than 256-bits and the key length isn't set, we round the length
|
528 |
+
* up to the closest valid key length, padding $key with null bytes. If the key is more than 256-bits, we trim the
|
529 |
+
* excess bits.
|
530 |
+
*
|
531 |
+
* If the key is not explicitly set, it'll be assumed to be all null bytes.
|
532 |
+
*
|
533 |
+
* @access public
|
534 |
+
* @param String $key
|
535 |
+
*/
|
536 |
+
function setKey($key)
|
537 |
+
{
|
538 |
+
$this->key = $key;
|
539 |
+
$this->changed = true;
|
540 |
+
}
|
541 |
+
|
542 |
+
/**
|
543 |
+
* Sets the initialization vector. (optional)
|
544 |
+
*
|
545 |
+
* SetIV is not required when CRYPT_RIJNDAEL_MODE_ECB is being used. If not explictly set, it'll be assumed
|
546 |
+
* to be all zero's.
|
547 |
+
*
|
548 |
+
* @access public
|
549 |
+
* @param String $iv
|
550 |
+
*/
|
551 |
+
function setIV($iv)
|
552 |
+
{
|
553 |
+
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, $this->block_size), $this->block_size, chr(0));;
|
554 |
+
}
|
555 |
+
|
556 |
+
/**
|
557 |
+
* Sets the key length
|
558 |
+
*
|
559 |
+
* Valid key lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
|
560 |
+
* 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
|
561 |
+
*
|
562 |
+
* @access public
|
563 |
+
* @param Integer $length
|
564 |
+
*/
|
565 |
+
function setKeyLength($length)
|
566 |
+
{
|
567 |
+
$length >>= 5;
|
568 |
+
if ($length > 8) {
|
569 |
+
$length = 8;
|
570 |
+
} else if ($length < 4) {
|
571 |
+
$length = 4;
|
572 |
+
}
|
573 |
+
$this->Nk = $length;
|
574 |
+
$this->key_size = $length << 2;
|
575 |
+
|
576 |
+
$this->explicit_key_length = true;
|
577 |
+
$this->changed = true;
|
578 |
+
}
|
579 |
+
|
580 |
+
/**
|
581 |
+
* Sets the block length
|
582 |
+
*
|
583 |
+
* Valid block lengths are 128, 160, 192, 224, and 256. If the length is less than 128, it will be rounded up to
|
584 |
+
* 128. If the length is greater then 128 and invalid, it will be rounded down to the closest valid amount.
|
585 |
+
*
|
586 |
+
* @access public
|
587 |
+
* @param Integer $length
|
588 |
+
*/
|
589 |
+
function setBlockLength($length)
|
590 |
+
{
|
591 |
+
$length >>= 5;
|
592 |
+
if ($length > 8) {
|
593 |
+
$length = 8;
|
594 |
+
} else if ($length < 4) {
|
595 |
+
$length = 4;
|
596 |
+
}
|
597 |
+
$this->Nb = $length;
|
598 |
+
$this->block_size = $length << 2;
|
599 |
+
$this->changed = true;
|
600 |
+
}
|
601 |
+
|
602 |
+
/**
|
603 |
+
* Generate CTR XOR encryption key
|
604 |
+
*
|
605 |
+
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
|
606 |
+
* plaintext / ciphertext in CTR mode.
|
607 |
+
*
|
608 |
+
* @see Crypt_Rijndael::decrypt()
|
609 |
+
* @see Crypt_Rijndael::encrypt()
|
610 |
+
* @access public
|
611 |
+
* @param Integer $length
|
612 |
+
* @param String $iv
|
613 |
+
*/
|
614 |
+
function _generate_xor($length, &$iv)
|
615 |
+
{
|
616 |
+
$xor = '';
|
617 |
+
$block_size = $this->block_size;
|
618 |
+
$num_blocks = floor(($length + ($block_size - 1)) / $block_size);
|
619 |
+
for ($i = 0; $i < $num_blocks; $i++) {
|
620 |
+
$xor.= $iv;
|
621 |
+
for ($j = 4; $j <= $block_size; $j+=4) {
|
622 |
+
$temp = substr($iv, -$j, 4);
|
623 |
+
switch ($temp) {
|
624 |
+
case "\xFF\xFF\xFF\xFF":
|
625 |
+
$iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
|
626 |
+
break;
|
627 |
+
case "\x7F\xFF\xFF\xFF":
|
628 |
+
$iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
|
629 |
+
break 2;
|
630 |
+
default:
|
631 |
+
extract(unpack('Ncount', $temp));
|
632 |
+
$iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
|
633 |
+
break 2;
|
634 |
+
}
|
635 |
+
}
|
636 |
+
}
|
637 |
+
|
638 |
+
return $xor;
|
639 |
+
}
|
640 |
+
|
641 |
+
/**
|
642 |
+
* Encrypts a message.
|
643 |
+
*
|
644 |
+
* $plaintext will be padded with additional bytes such that it's length is a multiple of the block size. Other Rjindael
|
645 |
+
* implementations may or may not pad in the same manner. Other common approaches to padding and the reasons why it's
|
646 |
+
* necessary are discussed in the following
|
647 |
+
* URL:
|
648 |
+
*
|
649 |
+
* {@link http://www.di-mgt.com.au/cryptopad.html http://www.di-mgt.com.au/cryptopad.html}
|
650 |
+
*
|
651 |
+
* An alternative to padding is to, separately, send the length of the file. This is what SSH, in fact, does.
|
652 |
+
* strlen($plaintext) will still need to be a multiple of 8, however, arbitrary values can be added to make it that
|
653 |
+
* length.
|
654 |
+
*
|
655 |
+
* @see Crypt_Rijndael::decrypt()
|
656 |
+
* @access public
|
657 |
+
* @param String $plaintext
|
658 |
+
*/
|
659 |
+
function encrypt($plaintext)
|
660 |
+
{
|
661 |
+
$this->_setup();
|
662 |
+
if ($this->paddable) {
|
663 |
+
$plaintext = $this->_pad($plaintext);
|
664 |
+
}
|
665 |
+
|
666 |
+
$block_size = $this->block_size;
|
667 |
+
$buffer = &$this->enbuffer;
|
668 |
+
$continuousBuffer = $this->continuousBuffer;
|
669 |
+
$ciphertext = '';
|
670 |
+
switch ($this->mode) {
|
671 |
+
case CRYPT_RIJNDAEL_MODE_ECB:
|
672 |
+
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
673 |
+
$ciphertext.= $this->_encryptBlock(substr($plaintext, $i, $block_size));
|
674 |
+
}
|
675 |
+
break;
|
676 |
+
case CRYPT_RIJNDAEL_MODE_CBC:
|
677 |
+
$xor = $this->encryptIV;
|
678 |
+
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
679 |
+
$block = substr($plaintext, $i, $block_size);
|
680 |
+
$block = $this->_encryptBlock($block ^ $xor);
|
681 |
+
$xor = $block;
|
682 |
+
$ciphertext.= $block;
|
683 |
+
}
|
684 |
+
if ($this->continuousBuffer) {
|
685 |
+
$this->encryptIV = $xor;
|
686 |
+
}
|
687 |
+
break;
|
688 |
+
case CRYPT_RIJNDAEL_MODE_CTR:
|
689 |
+
$xor = $this->encryptIV;
|
690 |
+
if (!empty($buffer)) {
|
691 |
+
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
692 |
+
$block = substr($plaintext, $i, $block_size);
|
693 |
+
$buffer.= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
|
694 |
+
$key = $this->_string_shift($buffer, $block_size);
|
695 |
+
$ciphertext.= $block ^ $key;
|
696 |
+
}
|
697 |
+
} else {
|
698 |
+
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
699 |
+
$block = substr($plaintext, $i, $block_size);
|
700 |
+
$key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
|
701 |
+
$ciphertext.= $block ^ $key;
|
702 |
+
}
|
703 |
+
}
|
704 |
+
if ($this->continuousBuffer) {
|
705 |
+
$this->encryptIV = $xor;
|
706 |
+
if ($start = strlen($plaintext) % $block_size) {
|
707 |
+
$buffer = substr($key, $start) . $buffer;
|
708 |
+
}
|
709 |
+
}
|
710 |
+
break;
|
711 |
+
case CRYPT_RIJNDAEL_MODE_CFB:
|
712 |
+
if (!empty($buffer['xor'])) {
|
713 |
+
$ciphertext = $plaintext ^ $buffer['xor'];
|
714 |
+
$iv = $buffer['encrypted'] . $ciphertext;
|
715 |
+
$start = strlen($ciphertext);
|
716 |
+
$buffer['encrypted'].= $ciphertext;
|
717 |
+
$buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
|
718 |
+
} else {
|
719 |
+
$ciphertext = '';
|
720 |
+
$iv = $this->encryptIV;
|
721 |
+
$start = 0;
|
722 |
+
}
|
723 |
+
|
724 |
+
for ($i = $start; $i < strlen($plaintext); $i+=$block_size) {
|
725 |
+
$block = substr($plaintext, $i, $block_size);
|
726 |
+
$xor = $this->_encryptBlock($iv);
|
727 |
+
$iv = $block ^ $xor;
|
728 |
+
if ($continuousBuffer && strlen($iv) != $block_size) {
|
729 |
+
$buffer = array(
|
730 |
+
'encrypted' => $iv,
|
731 |
+
'xor' => substr($xor, strlen($iv))
|
732 |
+
);
|
733 |
+
}
|
734 |
+
$ciphertext.= $iv;
|
735 |
+
}
|
736 |
+
|
737 |
+
if ($this->continuousBuffer) {
|
738 |
+
$this->encryptIV = $iv;
|
739 |
+
}
|
740 |
+
break;
|
741 |
+
case CRYPT_RIJNDAEL_MODE_OFB:
|
742 |
+
$xor = $this->encryptIV;
|
743 |
+
if (strlen($buffer)) {
|
744 |
+
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
745 |
+
$xor = $this->_encryptBlock($xor);
|
746 |
+
$buffer.= $xor;
|
747 |
+
$key = $this->_string_shift($buffer, $block_size);
|
748 |
+
$ciphertext.= substr($plaintext, $i, $block_size) ^ $key;
|
749 |
+
}
|
750 |
+
} else {
|
751 |
+
for ($i = 0; $i < strlen($plaintext); $i+=$block_size) {
|
752 |
+
$xor = $this->_encryptBlock($xor);
|
753 |
+
$ciphertext.= substr($plaintext, $i, $block_size) ^ $xor;
|
754 |
+
}
|
755 |
+
$key = $xor;
|
756 |
+
}
|
757 |
+
if ($this->continuousBuffer) {
|
758 |
+
$this->encryptIV = $xor;
|
759 |
+
if ($start = strlen($plaintext) % $block_size) {
|
760 |
+
$buffer = substr($key, $start) . $buffer;
|
761 |
+
}
|
762 |
+
}
|
763 |
+
}
|
764 |
+
|
765 |
+
return $ciphertext;
|
766 |
+
}
|
767 |
+
|
768 |
+
/**
|
769 |
+
* Decrypts a message.
|
770 |
+
*
|
771 |
+
* If strlen($ciphertext) is not a multiple of the block size, null bytes will be added to the end of the string until
|
772 |
+
* it is.
|
773 |
+
*
|
774 |
+
* @see Crypt_Rijndael::encrypt()
|
775 |
+
* @access public
|
776 |
+
* @param String $ciphertext
|
777 |
+
*/
|
778 |
+
function decrypt($ciphertext)
|
779 |
+
{
|
780 |
+
$this->_setup();
|
781 |
+
|
782 |
+
if ($this->paddable) {
|
783 |
+
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
|
784 |
+
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
785 |
+
$ciphertext = str_pad($ciphertext, strlen($ciphertext) + ($this->block_size - strlen($ciphertext) % $this->block_size) % $this->block_size, chr(0));
|
786 |
+
}
|
787 |
+
|
788 |
+
$block_size = $this->block_size;
|
789 |
+
$buffer = &$this->debuffer;
|
790 |
+
$continuousBuffer = $this->continuousBuffer;
|
791 |
+
$plaintext = '';
|
792 |
+
switch ($this->mode) {
|
793 |
+
case CRYPT_RIJNDAEL_MODE_ECB:
|
794 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
795 |
+
$plaintext.= $this->_decryptBlock(substr($ciphertext, $i, $block_size));
|
796 |
+
}
|
797 |
+
break;
|
798 |
+
case CRYPT_RIJNDAEL_MODE_CBC:
|
799 |
+
$xor = $this->decryptIV;
|
800 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
801 |
+
$block = substr($ciphertext, $i, $block_size);
|
802 |
+
$plaintext.= $this->_decryptBlock($block) ^ $xor;
|
803 |
+
$xor = $block;
|
804 |
+
}
|
805 |
+
if ($this->continuousBuffer) {
|
806 |
+
$this->decryptIV = $xor;
|
807 |
+
}
|
808 |
+
break;
|
809 |
+
case CRYPT_RIJNDAEL_MODE_CTR:
|
810 |
+
$xor = $this->decryptIV;
|
811 |
+
if (strlen($buffer)) {
|
812 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
813 |
+
$block = substr($ciphertext, $i, $block_size);
|
814 |
+
$buffer.= $this->_encryptBlock($this->_generate_xor($block_size, $xor));
|
815 |
+
$key = $this->_string_shift($buffer, $block_size);
|
816 |
+
$plaintext.= $block ^ $key;
|
817 |
+
}
|
818 |
+
} else {
|
819 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
820 |
+
$block = substr($ciphertext, $i, $block_size);
|
821 |
+
$key = $this->_encryptBlock($this->_generate_xor($block_size, $xor));
|
822 |
+
$plaintext.= $block ^ $key;
|
823 |
+
}
|
824 |
+
}
|
825 |
+
if ($this->continuousBuffer) {
|
826 |
+
$this->decryptIV = $xor;
|
827 |
+
if ($start = strlen($ciphertext) % $block_size) {
|
828 |
+
$buffer = substr($key, $start) . $buffer;
|
829 |
+
}
|
830 |
+
}
|
831 |
+
break;
|
832 |
+
case CRYPT_RIJNDAEL_MODE_CFB:
|
833 |
+
if (!empty($buffer['ciphertext'])) {
|
834 |
+
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
|
835 |
+
$buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
|
836 |
+
if (strlen($buffer['ciphertext']) == $block_size) {
|
837 |
+
$xor = $this->_encryptBlock($buffer['ciphertext']);
|
838 |
+
$buffer['ciphertext'] = '';
|
839 |
+
}
|
840 |
+
$start = strlen($plaintext);
|
841 |
+
$block = $this->decryptIV;
|
842 |
+
} else {
|
843 |
+
$plaintext = '';
|
844 |
+
$xor = $this->_encryptBlock($this->decryptIV);
|
845 |
+
$start = 0;
|
846 |
+
}
|
847 |
+
|
848 |
+
for ($i = $start; $i < strlen($ciphertext); $i+=$block_size) {
|
849 |
+
$block = substr($ciphertext, $i, $block_size);
|
850 |
+
$plaintext.= $block ^ $xor;
|
851 |
+
if ($continuousBuffer && strlen($block) != $block_size) {
|
852 |
+
$buffer['ciphertext'].= $block;
|
853 |
+
$block = $xor;
|
854 |
+
} else if (strlen($block) == $block_size) {
|
855 |
+
$xor = $this->_encryptBlock($block);
|
856 |
+
}
|
857 |
+
}
|
858 |
+
if ($this->continuousBuffer) {
|
859 |
+
$this->decryptIV = $block;
|
860 |
+
}
|
861 |
+
break;
|
862 |
+
case CRYPT_RIJNDAEL_MODE_OFB:
|
863 |
+
$xor = $this->decryptIV;
|
864 |
+
if (strlen($buffer)) {
|
865 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
866 |
+
$xor = $this->_encryptBlock($xor);
|
867 |
+
$buffer.= $xor;
|
868 |
+
$key = $this->_string_shift($buffer, $block_size);
|
869 |
+
$plaintext.= substr($ciphertext, $i, $block_size) ^ $key;
|
870 |
+
}
|
871 |
+
} else {
|
872 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=$block_size) {
|
873 |
+
$xor = $this->_encryptBlock($xor);
|
874 |
+
$plaintext.= substr($ciphertext, $i, $block_size) ^ $xor;
|
875 |
+
}
|
876 |
+
$key = $xor;
|
877 |
+
}
|
878 |
+
if ($this->continuousBuffer) {
|
879 |
+
$this->decryptIV = $xor;
|
880 |
+
if ($start = strlen($ciphertext) % $block_size) {
|
881 |
+
$buffer = substr($key, $start) . $buffer;
|
882 |
+
}
|
883 |
+
}
|
884 |
+
}
|
885 |
+
|
886 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
887 |
+
}
|
888 |
+
|
889 |
+
/**
|
890 |
+
* Encrypts a block
|
891 |
+
*
|
892 |
+
* @access private
|
893 |
+
* @param String $in
|
894 |
+
* @return String
|
895 |
+
*/
|
896 |
+
function _encryptBlock($in)
|
897 |
+
{
|
898 |
+
$state = array();
|
899 |
+
$words = unpack('N*word', $in);
|
900 |
+
|
901 |
+
$w = $this->w;
|
902 |
+
$t0 = $this->t0;
|
903 |
+
$t1 = $this->t1;
|
904 |
+
$t2 = $this->t2;
|
905 |
+
$t3 = $this->t3;
|
906 |
+
$Nb = $this->Nb;
|
907 |
+
$Nr = $this->Nr;
|
908 |
+
$c = $this->c;
|
909 |
+
|
910 |
+
// addRoundKey
|
911 |
+
$i = 0;
|
912 |
+
foreach ($words as $word) {
|
913 |
+
$state[] = $word ^ $w[0][$i++];
|
914 |
+
}
|
915 |
+
|
916 |
+
// fips-197.pdf#page=19, "Figure 5. Pseudo Code for the Cipher", states that this loop has four components -
|
917 |
+
// subBytes, shiftRows, mixColumns, and addRoundKey. fips-197.pdf#page=30, "Implementation Suggestions Regarding
|
918 |
+
// Various Platforms" suggests that performs enhanced implementations are described in Rijndael-ammended.pdf.
|
919 |
+
// Rijndael-ammended.pdf#page=20, "Implementation aspects / 32-bit processor", discusses such an optimization.
|
920 |
+
// Unfortunately, the description given there is not quite correct. Per aes.spec.v316.pdf#page=19 [1],
|
921 |
+
// equation (7.4.7) is supposed to use addition instead of subtraction, so we'll do that here, as well.
|
922 |
+
|
923 |
+
// [1] http://fp.gladman.plus.com/cryptography_technology/rijndael/aes.spec.v316.pdf
|
924 |
+
$temp = array();
|
925 |
+
for ($round = 1; $round < $Nr; $round++) {
|
926 |
+
$i = 0; // $c[0] == 0
|
927 |
+
$j = $c[1];
|
928 |
+
$k = $c[2];
|
929 |
+
$l = $c[3];
|
930 |
+
|
931 |
+
while ($i < $this->Nb) {
|
932 |
+
$temp[$i] = $t0[$state[$i] & 0xFF000000] ^
|
933 |
+
$t1[$state[$j] & 0x00FF0000] ^
|
934 |
+
$t2[$state[$k] & 0x0000FF00] ^
|
935 |
+
$t3[$state[$l] & 0x000000FF] ^
|
936 |
+
$w[$round][$i];
|
937 |
+
$i++;
|
938 |
+
$j = ($j + 1) % $Nb;
|
939 |
+
$k = ($k + 1) % $Nb;
|
940 |
+
$l = ($l + 1) % $Nb;
|
941 |
+
}
|
942 |
+
|
943 |
+
for ($i = 0; $i < $Nb; $i++) {
|
944 |
+
$state[$i] = $temp[$i];
|
945 |
+
}
|
946 |
+
}
|
947 |
+
|
948 |
+
// subWord
|
949 |
+
for ($i = 0; $i < $Nb; $i++) {
|
950 |
+
$state[$i] = $this->_subWord($state[$i]);
|
951 |
+
}
|
952 |
+
|
953 |
+
// shiftRows + addRoundKey
|
954 |
+
$i = 0; // $c[0] == 0
|
955 |
+
$j = $c[1];
|
956 |
+
$k = $c[2];
|
957 |
+
$l = $c[3];
|
958 |
+
while ($i < $this->Nb) {
|
959 |
+
$temp[$i] = ($state[$i] & 0xFF000000) ^
|
960 |
+
($state[$j] & 0x00FF0000) ^
|
961 |
+
($state[$k] & 0x0000FF00) ^
|
962 |
+
($state[$l] & 0x000000FF) ^
|
963 |
+
$w[$Nr][$i];
|
964 |
+
$i++;
|
965 |
+
$j = ($j + 1) % $Nb;
|
966 |
+
$k = ($k + 1) % $Nb;
|
967 |
+
$l = ($l + 1) % $Nb;
|
968 |
+
}
|
969 |
+
$state = $temp;
|
970 |
+
|
971 |
+
array_unshift($state, 'N*');
|
972 |
+
|
973 |
+
return call_user_func_array('pack', $state);
|
974 |
+
}
|
975 |
+
|
976 |
+
/**
|
977 |
+
* Decrypts a block
|
978 |
+
*
|
979 |
+
* @access private
|
980 |
+
* @param String $in
|
981 |
+
* @return String
|
982 |
+
*/
|
983 |
+
function _decryptBlock($in)
|
984 |
+
{
|
985 |
+
$state = array();
|
986 |
+
$words = unpack('N*word', $in);
|
987 |
+
|
988 |
+
$num_states = count($state);
|
989 |
+
$dw = $this->dw;
|
990 |
+
$dt0 = $this->dt0;
|
991 |
+
$dt1 = $this->dt1;
|
992 |
+
$dt2 = $this->dt2;
|
993 |
+
$dt3 = $this->dt3;
|
994 |
+
$Nb = $this->Nb;
|
995 |
+
$Nr = $this->Nr;
|
996 |
+
$c = $this->c;
|
997 |
+
|
998 |
+
// addRoundKey
|
999 |
+
$i = 0;
|
1000 |
+
foreach ($words as $word) {
|
1001 |
+
$state[] = $word ^ $dw[$Nr][$i++];
|
1002 |
+
}
|
1003 |
+
|
1004 |
+
$temp = array();
|
1005 |
+
for ($round = $Nr - 1; $round > 0; $round--) {
|
1006 |
+
$i = 0; // $c[0] == 0
|
1007 |
+
$j = $Nb - $c[1];
|
1008 |
+
$k = $Nb - $c[2];
|
1009 |
+
$l = $Nb - $c[3];
|
1010 |
+
|
1011 |
+
while ($i < $Nb) {
|
1012 |
+
$temp[$i] = $dt0[$state[$i] & 0xFF000000] ^
|
1013 |
+
$dt1[$state[$j] & 0x00FF0000] ^
|
1014 |
+
$dt2[$state[$k] & 0x0000FF00] ^
|
1015 |
+
$dt3[$state[$l] & 0x000000FF] ^
|
1016 |
+
$dw[$round][$i];
|
1017 |
+
$i++;
|
1018 |
+
$j = ($j + 1) % $Nb;
|
1019 |
+
$k = ($k + 1) % $Nb;
|
1020 |
+
$l = ($l + 1) % $Nb;
|
1021 |
+
}
|
1022 |
+
|
1023 |
+
for ($i = 0; $i < $Nb; $i++) {
|
1024 |
+
$state[$i] = $temp[$i];
|
1025 |
+
}
|
1026 |
+
}
|
1027 |
+
|
1028 |
+
// invShiftRows + invSubWord + addRoundKey
|
1029 |
+
$i = 0; // $c[0] == 0
|
1030 |
+
$j = $Nb - $c[1];
|
1031 |
+
$k = $Nb - $c[2];
|
1032 |
+
$l = $Nb - $c[3];
|
1033 |
+
|
1034 |
+
while ($i < $Nb) {
|
1035 |
+
$temp[$i] = $dw[0][$i] ^
|
1036 |
+
$this->_invSubWord(($state[$i] & 0xFF000000) |
|
1037 |
+
($state[$j] & 0x00FF0000) |
|
1038 |
+
($state[$k] & 0x0000FF00) |
|
1039 |
+
($state[$l] & 0x000000FF));
|
1040 |
+
$i++;
|
1041 |
+
$j = ($j + 1) % $Nb;
|
1042 |
+
$k = ($k + 1) % $Nb;
|
1043 |
+
$l = ($l + 1) % $Nb;
|
1044 |
+
}
|
1045 |
+
|
1046 |
+
$state = $temp;
|
1047 |
+
|
1048 |
+
array_unshift($state, 'N*');
|
1049 |
+
|
1050 |
+
return call_user_func_array('pack', $state);
|
1051 |
+
}
|
1052 |
+
|
1053 |
+
/**
|
1054 |
+
* Setup Rijndael
|
1055 |
+
*
|
1056 |
+
* Validates all the variables and calculates $Nr - the number of rounds that need to be performed - and $w - the key
|
1057 |
+
* key schedule.
|
1058 |
+
*
|
1059 |
+
* @access private
|
1060 |
+
*/
|
1061 |
+
function _setup()
|
1062 |
+
{
|
1063 |
+
// Each number in $rcon is equal to the previous number multiplied by two in Rijndael's finite field.
|
1064 |
+
// See http://en.wikipedia.org/wiki/Finite_field_arithmetic#Multiplicative_inverse
|
1065 |
+
static $rcon = array(0,
|
1066 |
+
0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
|
1067 |
+
0x20000000, 0x40000000, 0x80000000, 0x1B000000, 0x36000000,
|
1068 |
+
0x6C000000, 0xD8000000, 0xAB000000, 0x4D000000, 0x9A000000,
|
1069 |
+
0x2F000000, 0x5E000000, 0xBC000000, 0x63000000, 0xC6000000,
|
1070 |
+
0x97000000, 0x35000000, 0x6A000000, 0xD4000000, 0xB3000000,
|
1071 |
+
0x7D000000, 0xFA000000, 0xEF000000, 0xC5000000, 0x91000000
|
1072 |
+
);
|
1073 |
+
|
1074 |
+
if (!$this->changed) {
|
1075 |
+
return;
|
1076 |
+
}
|
1077 |
+
|
1078 |
+
if (!$this->explicit_key_length) {
|
1079 |
+
// we do >> 2, here, and not >> 5, as we do above, since strlen($this->key) tells us the number of bytes - not bits
|
1080 |
+
$length = strlen($this->key) >> 2;
|
1081 |
+
if ($length > 8) {
|
1082 |
+
$length = 8;
|
1083 |
+
} else if ($length < 4) {
|
1084 |
+
$length = 4;
|
1085 |
+
}
|
1086 |
+
$this->Nk = $length;
|
1087 |
+
$this->key_size = $length << 2;
|
1088 |
+
}
|
1089 |
+
|
1090 |
+
$this->key = str_pad(substr($this->key, 0, $this->key_size), $this->key_size, chr(0));
|
1091 |
+
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($this->iv, 0, $this->block_size), $this->block_size, chr(0));
|
1092 |
+
|
1093 |
+
// see Rijndael-ammended.pdf#page=44
|
1094 |
+
$this->Nr = max($this->Nk, $this->Nb) + 6;
|
1095 |
+
|
1096 |
+
// shift offsets for Nb = 5, 7 are defined in Rijndael-ammended.pdf#page=44,
|
1097 |
+
// "Table 8: Shift offsets in Shiftrow for the alternative block lengths"
|
1098 |
+
// shift offsets for Nb = 4, 6, 8 are defined in Rijndael-ammended.pdf#page=14,
|
1099 |
+
// "Table 2: Shift offsets for different block lengths"
|
1100 |
+
switch ($this->Nb) {
|
1101 |
+
case 4:
|
1102 |
+
case 5:
|
1103 |
+
case 6:
|
1104 |
+
$this->c = array(0, 1, 2, 3);
|
1105 |
+
break;
|
1106 |
+
case 7:
|
1107 |
+
$this->c = array(0, 1, 2, 4);
|
1108 |
+
break;
|
1109 |
+
case 8:
|
1110 |
+
$this->c = array(0, 1, 3, 4);
|
1111 |
+
}
|
1112 |
+
|
1113 |
+
$key = $this->key;
|
1114 |
+
|
1115 |
+
$w = array_values(unpack('N*words', $key));
|
1116 |
+
|
1117 |
+
$length = $this->Nb * ($this->Nr + 1);
|
1118 |
+
for ($i = $this->Nk; $i < $length; $i++) {
|
1119 |
+
$temp = $w[$i - 1];
|
1120 |
+
if ($i % $this->Nk == 0) {
|
1121 |
+
// according to <http://php.net/language.types.integer>, "the size of an integer is platform-dependent".
|
1122 |
+
// on a 32-bit machine, it's 32-bits, and on a 64-bit machine, it's 64-bits. on a 32-bit machine,
|
1123 |
+
// 0xFFFFFFFF << 8 == 0xFFFFFF00, but on a 64-bit machine, it equals 0xFFFFFFFF00. as such, doing 'and'
|
1124 |
+
// with 0xFFFFFFFF (or 0xFFFFFF00) on a 32-bit machine is unnecessary, but on a 64-bit machine, it is.
|
1125 |
+
$temp = (($temp << 8) & 0xFFFFFF00) | (($temp >> 24) & 0x000000FF); // rotWord
|
1126 |
+
$temp = $this->_subWord($temp) ^ $rcon[$i / $this->Nk];
|
1127 |
+
} else if ($this->Nk > 6 && $i % $this->Nk == 4) {
|
1128 |
+
$temp = $this->_subWord($temp);
|
1129 |
+
}
|
1130 |
+
$w[$i] = $w[$i - $this->Nk] ^ $temp;
|
1131 |
+
}
|
1132 |
+
|
1133 |
+
// convert the key schedule from a vector of $Nb * ($Nr + 1) length to a matrix with $Nr + 1 rows and $Nb columns
|
1134 |
+
// and generate the inverse key schedule. more specifically,
|
1135 |
+
// according to <http://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf#page=23> (section 5.3.3),
|
1136 |
+
// "The key expansion for the Inverse Cipher is defined as follows:
|
1137 |
+
// 1. Apply the Key Expansion.
|
1138 |
+
// 2. Apply InvMixColumn to all Round Keys except the first and the last one."
|
1139 |
+
// also, see fips-197.pdf#page=27, "5.3.5 Equivalent Inverse Cipher"
|
1140 |
+
$temp = array();
|
1141 |
+
for ($i = $row = $col = 0; $i < $length; $i++, $col++) {
|
1142 |
+
if ($col == $this->Nb) {
|
1143 |
+
if ($row == 0) {
|
1144 |
+
$this->dw[0] = $this->w[0];
|
1145 |
+
} else {
|
1146 |
+
// subWord + invMixColumn + invSubWord = invMixColumn
|
1147 |
+
$j = 0;
|
1148 |
+
while ($j < $this->Nb) {
|
1149 |
+
$dw = $this->_subWord($this->w[$row][$j]);
|
1150 |
+
$temp[$j] = $this->dt0[$dw & 0xFF000000] ^
|
1151 |
+
$this->dt1[$dw & 0x00FF0000] ^
|
1152 |
+
$this->dt2[$dw & 0x0000FF00] ^
|
1153 |
+
$this->dt3[$dw & 0x000000FF];
|
1154 |
+
$j++;
|
1155 |
+
}
|
1156 |
+
$this->dw[$row] = $temp;
|
1157 |
+
}
|
1158 |
+
|
1159 |
+
$col = 0;
|
1160 |
+
$row++;
|
1161 |
+
}
|
1162 |
+
$this->w[$row][$col] = $w[$i];
|
1163 |
+
}
|
1164 |
+
|
1165 |
+
$this->dw[$row] = $this->w[$row];
|
1166 |
+
|
1167 |
+
$this->changed = false;
|
1168 |
+
}
|
1169 |
+
|
1170 |
+
/**
|
1171 |
+
* Performs S-Box substitutions
|
1172 |
+
*
|
1173 |
+
* @access private
|
1174 |
+
*/
|
1175 |
+
function _subWord($word)
|
1176 |
+
{
|
1177 |
+
static $sbox0, $sbox1, $sbox2, $sbox3;
|
1178 |
+
|
1179 |
+
if (empty($sbox0)) {
|
1180 |
+
$sbox0 = array(
|
1181 |
+
0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B, 0xFE, 0xD7, 0xAB, 0x76,
|
1182 |
+
0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0, 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0,
|
1183 |
+
0xB7, 0xFD, 0x93, 0x26, 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
|
1184 |
+
0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2, 0xEB, 0x27, 0xB2, 0x75,
|
1185 |
+
0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0, 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84,
|
1186 |
+
0x53, 0xD1, 0x00, 0xED, 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
|
1187 |
+
0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F, 0x50, 0x3C, 0x9F, 0xA8,
|
1188 |
+
0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5, 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2,
|
1189 |
+
0xCD, 0x0C, 0x13, 0xEC, 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
|
1190 |
+
0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14, 0xDE, 0x5E, 0x0B, 0xDB,
|
1191 |
+
0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C, 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79,
|
1192 |
+
0xE7, 0xC8, 0x37, 0x6D, 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
|
1193 |
+
0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F, 0x4B, 0xBD, 0x8B, 0x8A,
|
1194 |
+
0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E, 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E,
|
1195 |
+
0xE1, 0xF8, 0x98, 0x11, 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
|
1196 |
+
0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F, 0xB0, 0x54, 0xBB, 0x16
|
1197 |
+
);
|
1198 |
+
|
1199 |
+
$sbox1 = array();
|
1200 |
+
$sbox2 = array();
|
1201 |
+
$sbox3 = array();
|
1202 |
+
|
1203 |
+
for ($i = 0; $i < 256; $i++) {
|
1204 |
+
$sbox1[$i << 8] = $sbox0[$i] << 8;
|
1205 |
+
$sbox2[$i << 16] = $sbox0[$i] << 16;
|
1206 |
+
$sbox3[$i << 24] = $sbox0[$i] << 24;
|
1207 |
+
}
|
1208 |
+
}
|
1209 |
+
|
1210 |
+
return $sbox0[$word & 0x000000FF] |
|
1211 |
+
$sbox1[$word & 0x0000FF00] |
|
1212 |
+
$sbox2[$word & 0x00FF0000] |
|
1213 |
+
$sbox3[$word & 0xFF000000];
|
1214 |
+
}
|
1215 |
+
|
1216 |
+
/**
|
1217 |
+
* Performs inverse S-Box substitutions
|
1218 |
+
*
|
1219 |
+
* @access private
|
1220 |
+
*/
|
1221 |
+
function _invSubWord($word)
|
1222 |
+
{
|
1223 |
+
static $sbox0, $sbox1, $sbox2, $sbox3;
|
1224 |
+
|
1225 |
+
if (empty($sbox0)) {
|
1226 |
+
$sbox0 = array(
|
1227 |
+
0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E, 0x81, 0xF3, 0xD7, 0xFB,
|
1228 |
+
0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87, 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB,
|
1229 |
+
0x54, 0x7B, 0x94, 0x32, 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
|
1230 |
+
0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49, 0x6D, 0x8B, 0xD1, 0x25,
|
1231 |
+
0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16, 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92,
|
1232 |
+
0x6C, 0x70, 0x48, 0x50, 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
|
1233 |
+
0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05, 0xB8, 0xB3, 0x45, 0x06,
|
1234 |
+
0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02, 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B,
|
1235 |
+
0x3A, 0x91, 0x11, 0x41, 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
|
1236 |
+
0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8, 0x1C, 0x75, 0xDF, 0x6E,
|
1237 |
+
0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89, 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B,
|
1238 |
+
0xFC, 0x56, 0x3E, 0x4B, 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
|
1239 |
+
0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59, 0x27, 0x80, 0xEC, 0x5F,
|
1240 |
+
0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D, 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF,
|
1241 |
+
0xA0, 0xE0, 0x3B, 0x4D, 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
|
1242 |
+
0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63, 0x55, 0x21, 0x0C, 0x7D
|
1243 |
+
);
|
1244 |
+
|
1245 |
+
$sbox1 = array();
|
1246 |
+
$sbox2 = array();
|
1247 |
+
$sbox3 = array();
|
1248 |
+
|
1249 |
+
for ($i = 0; $i < 256; $i++) {
|
1250 |
+
$sbox1[$i << 8] = $sbox0[$i] << 8;
|
1251 |
+
$sbox2[$i << 16] = $sbox0[$i] << 16;
|
1252 |
+
$sbox3[$i << 24] = $sbox0[$i] << 24;
|
1253 |
+
}
|
1254 |
+
}
|
1255 |
+
|
1256 |
+
return $sbox0[$word & 0x000000FF] |
|
1257 |
+
$sbox1[$word & 0x0000FF00] |
|
1258 |
+
$sbox2[$word & 0x00FF0000] |
|
1259 |
+
$sbox3[$word & 0xFF000000];
|
1260 |
+
}
|
1261 |
+
|
1262 |
+
/**
|
1263 |
+
* Pad "packets".
|
1264 |
+
*
|
1265 |
+
* Rijndael works by encrypting between sixteen and thirty-two bytes at a time, provided that number is also a multiple
|
1266 |
+
* of four. If you ever need to encrypt or decrypt something that isn't of the proper length, it becomes necessary to
|
1267 |
+
* pad the input so that it is of the proper length.
|
1268 |
+
*
|
1269 |
+
* Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH,
|
1270 |
+
* where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
|
1271 |
+
* away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
|
1272 |
+
* transmitted separately)
|
1273 |
+
*
|
1274 |
+
* @see Crypt_Rijndael::disablePadding()
|
1275 |
+
* @access public
|
1276 |
+
*/
|
1277 |
+
function enablePadding()
|
1278 |
+
{
|
1279 |
+
$this->padding = true;
|
1280 |
+
}
|
1281 |
+
|
1282 |
+
/**
|
1283 |
+
* Do not pad packets.
|
1284 |
+
*
|
1285 |
+
* @see Crypt_Rijndael::enablePadding()
|
1286 |
+
* @access public
|
1287 |
+
*/
|
1288 |
+
function disablePadding()
|
1289 |
+
{
|
1290 |
+
$this->padding = false;
|
1291 |
+
}
|
1292 |
+
|
1293 |
+
/**
|
1294 |
+
* Pads a string
|
1295 |
+
*
|
1296 |
+
* Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize.
|
1297 |
+
* $block_size - (strlen($text) % $block_size) bytes are added, each of which is equal to
|
1298 |
+
* chr($block_size - (strlen($text) % $block_size)
|
1299 |
+
*
|
1300 |
+
* If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
|
1301 |
+
* and padding will, hence forth, be enabled.
|
1302 |
+
*
|
1303 |
+
* @see Crypt_Rijndael::_unpad()
|
1304 |
+
* @access private
|
1305 |
+
*/
|
1306 |
+
function _pad($text)
|
1307 |
+
{
|
1308 |
+
$length = strlen($text);
|
1309 |
+
|
1310 |
+
if (!$this->padding) {
|
1311 |
+
if ($length % $this->block_size == 0) {
|
1312 |
+
return $text;
|
1313 |
+
} else {
|
1314 |
+
user_error("The plaintext's length ($length) is not a multiple of the block size ({$this->block_size})", E_USER_NOTICE);
|
1315 |
+
$this->padding = true;
|
1316 |
+
}
|
1317 |
+
}
|
1318 |
+
|
1319 |
+
$pad = $this->block_size - ($length % $this->block_size);
|
1320 |
+
|
1321 |
+
return str_pad($text, $length + $pad, chr($pad));
|
1322 |
+
}
|
1323 |
+
|
1324 |
+
/**
|
1325 |
+
* Unpads a string.
|
1326 |
+
*
|
1327 |
+
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
|
1328 |
+
* and false will be returned.
|
1329 |
+
*
|
1330 |
+
* @see Crypt_Rijndael::_pad()
|
1331 |
+
* @access private
|
1332 |
+
*/
|
1333 |
+
function _unpad($text)
|
1334 |
+
{
|
1335 |
+
if (!$this->padding) {
|
1336 |
+
return $text;
|
1337 |
+
}
|
1338 |
+
|
1339 |
+
$length = ord($text[strlen($text) - 1]);
|
1340 |
+
|
1341 |
+
if (!$length || $length > $this->block_size) {
|
1342 |
+
return false;
|
1343 |
+
}
|
1344 |
+
|
1345 |
+
return substr($text, 0, -$length);
|
1346 |
+
}
|
1347 |
+
|
1348 |
+
/**
|
1349 |
+
* Treat consecutive "packets" as if they are a continuous buffer.
|
1350 |
+
*
|
1351 |
+
* Say you have a 32-byte plaintext $plaintext. Using the default behavior, the two following code snippets
|
1352 |
+
* will yield different outputs:
|
1353 |
+
*
|
1354 |
+
* <code>
|
1355 |
+
* echo $rijndael->encrypt(substr($plaintext, 0, 16));
|
1356 |
+
* echo $rijndael->encrypt(substr($plaintext, 16, 16));
|
1357 |
+
* </code>
|
1358 |
+
* <code>
|
1359 |
+
* echo $rijndael->encrypt($plaintext);
|
1360 |
+
* </code>
|
1361 |
+
*
|
1362 |
+
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
|
1363 |
+
* another, as demonstrated with the following:
|
1364 |
+
*
|
1365 |
+
* <code>
|
1366 |
+
* $rijndael->encrypt(substr($plaintext, 0, 16));
|
1367 |
+
* echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
|
1368 |
+
* </code>
|
1369 |
+
* <code>
|
1370 |
+
* echo $rijndael->decrypt($des->encrypt(substr($plaintext, 16, 16)));
|
1371 |
+
* </code>
|
1372 |
+
*
|
1373 |
+
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
|
1374 |
+
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
|
1375 |
+
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
|
1376 |
+
*
|
1377 |
+
* Put another way, when the continuous buffer is enabled, the state of the Crypt_Rijndael() object changes after each
|
1378 |
+
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
|
1379 |
+
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
|
1380 |
+
* however, they are also less intuitive and more likely to cause you problems.
|
1381 |
+
*
|
1382 |
+
* @see Crypt_Rijndael::disableContinuousBuffer()
|
1383 |
+
* @access public
|
1384 |
+
*/
|
1385 |
+
function enableContinuousBuffer()
|
1386 |
+
{
|
1387 |
+
$this->continuousBuffer = true;
|
1388 |
+
}
|
1389 |
+
|
1390 |
+
/**
|
1391 |
+
* Treat consecutive packets as if they are a discontinuous buffer.
|
1392 |
+
*
|
1393 |
+
* The default behavior.
|
1394 |
+
*
|
1395 |
+
* @see Crypt_Rijndael::enableContinuousBuffer()
|
1396 |
+
* @access public
|
1397 |
+
*/
|
1398 |
+
function disableContinuousBuffer()
|
1399 |
+
{
|
1400 |
+
$this->continuousBuffer = false;
|
1401 |
+
$this->encryptIV = $this->iv;
|
1402 |
+
$this->decryptIV = $this->iv;
|
1403 |
+
}
|
1404 |
+
|
1405 |
+
/**
|
1406 |
+
* String Shift
|
1407 |
+
*
|
1408 |
+
* Inspired by array_shift
|
1409 |
+
*
|
1410 |
+
* @param String $string
|
1411 |
+
* @param optional Integer $index
|
1412 |
+
* @return String
|
1413 |
+
* @access private
|
1414 |
+
*/
|
1415 |
+
function _string_shift(&$string, $index = 1)
|
1416 |
+
{
|
1417 |
+
$substr = substr($string, 0, $index);
|
1418 |
+
$string = substr($string, $index);
|
1419 |
+
return $substr;
|
1420 |
+
}
|
1421 |
+
}
|
1422 |
+
|
1423 |
+
// vim: ts=4:sw=4:et:
|
1424 |
+
// vim6: fdl=1:
|
classes/phpseclib/Crypt/TripleDES.php
ADDED
@@ -0,0 +1,1009 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of Triple DES.
|
6 |
+
*
|
7 |
+
* Uses mcrypt, if available, and an internal implementation, otherwise. Operates in the EDE3 mode (encrypt-decrypt-encrypt).
|
8 |
+
*
|
9 |
+
* PHP versions 4 and 5
|
10 |
+
*
|
11 |
+
* Here's a short example of how to use this library:
|
12 |
+
* <code>
|
13 |
+
* <?php
|
14 |
+
* include('Crypt/TripleDES.php');
|
15 |
+
*
|
16 |
+
* $des = new Crypt_TripleDES();
|
17 |
+
*
|
18 |
+
* $des->setKey('abcdefghijklmnopqrstuvwx');
|
19 |
+
*
|
20 |
+
* $size = 10 * 1024;
|
21 |
+
* $plaintext = '';
|
22 |
+
* for ($i = 0; $i < $size; $i++) {
|
23 |
+
* $plaintext.= 'a';
|
24 |
+
* }
|
25 |
+
*
|
26 |
+
* echo $des->decrypt($des->encrypt($plaintext));
|
27 |
+
* ?>
|
28 |
+
* </code>
|
29 |
+
*
|
30 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
31 |
+
* of this software and associated documentation files (the "Software"), to deal
|
32 |
+
* in the Software without restriction, including without limitation the rights
|
33 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
34 |
+
* copies of the Software, and to permit persons to whom the Software is
|
35 |
+
* furnished to do so, subject to the following conditions:
|
36 |
+
*
|
37 |
+
* The above copyright notice and this permission notice shall be included in
|
38 |
+
* all copies or substantial portions of the Software.
|
39 |
+
*
|
40 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
41 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
42 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
43 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
44 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
45 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
46 |
+
* THE SOFTWARE.
|
47 |
+
*
|
48 |
+
* @category Crypt
|
49 |
+
* @package Crypt_TripleDES
|
50 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
51 |
+
* @copyright MMVII Jim Wigginton
|
52 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
53 |
+
* @version $Id: TripleDES.php,v 1.13 2010/02/26 03:40:25 terrafrost Exp $
|
54 |
+
* @link http://phpseclib.sourceforge.net
|
55 |
+
*/
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Include Crypt_DES
|
59 |
+
*/
|
60 |
+
require_once('DES.php');
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Encrypt / decrypt using inner chaining
|
64 |
+
*
|
65 |
+
* Inner chaining is used by SSH-1 and is generally considered to be less secure then outer chaining (CRYPT_DES_MODE_CBC3).
|
66 |
+
*/
|
67 |
+
define('CRYPT_DES_MODE_3CBC', -2);
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Encrypt / decrypt using outer chaining
|
71 |
+
*
|
72 |
+
* Outer chaining is used by SSH-2 and when the mode is set to CRYPT_DES_MODE_CBC.
|
73 |
+
*/
|
74 |
+
define('CRYPT_DES_MODE_CBC3', CRYPT_DES_MODE_CBC);
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Pure-PHP implementation of Triple DES.
|
78 |
+
*
|
79 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
80 |
+
* @version 0.1.0
|
81 |
+
* @access public
|
82 |
+
* @package Crypt_TerraDES
|
83 |
+
*/
|
84 |
+
class Crypt_TripleDES {
|
85 |
+
/**
|
86 |
+
* The Three Keys
|
87 |
+
*
|
88 |
+
* @see Crypt_TripleDES::setKey()
|
89 |
+
* @var String
|
90 |
+
* @access private
|
91 |
+
*/
|
92 |
+
var $key = "\0\0\0\0\0\0\0\0";
|
93 |
+
|
94 |
+
/**
|
95 |
+
* The Encryption Mode
|
96 |
+
*
|
97 |
+
* @see Crypt_TripleDES::Crypt_TripleDES()
|
98 |
+
* @var Integer
|
99 |
+
* @access private
|
100 |
+
*/
|
101 |
+
var $mode = CRYPT_DES_MODE_CBC;
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Continuous Buffer status
|
105 |
+
*
|
106 |
+
* @see Crypt_TripleDES::enableContinuousBuffer()
|
107 |
+
* @var Boolean
|
108 |
+
* @access private
|
109 |
+
*/
|
110 |
+
var $continuousBuffer = false;
|
111 |
+
|
112 |
+
/**
|
113 |
+
* Padding status
|
114 |
+
*
|
115 |
+
* @see Crypt_TripleDES::enablePadding()
|
116 |
+
* @var Boolean
|
117 |
+
* @access private
|
118 |
+
*/
|
119 |
+
var $padding = true;
|
120 |
+
|
121 |
+
/**
|
122 |
+
* The Initialization Vector
|
123 |
+
*
|
124 |
+
* @see Crypt_TripleDES::setIV()
|
125 |
+
* @var String
|
126 |
+
* @access private
|
127 |
+
*/
|
128 |
+
var $iv = "\0\0\0\0\0\0\0\0";
|
129 |
+
|
130 |
+
/**
|
131 |
+
* A "sliding" Initialization Vector
|
132 |
+
*
|
133 |
+
* @see Crypt_TripleDES::enableContinuousBuffer()
|
134 |
+
* @var String
|
135 |
+
* @access private
|
136 |
+
*/
|
137 |
+
var $encryptIV = "\0\0\0\0\0\0\0\0";
|
138 |
+
|
139 |
+
/**
|
140 |
+
* A "sliding" Initialization Vector
|
141 |
+
*
|
142 |
+
* @see Crypt_TripleDES::enableContinuousBuffer()
|
143 |
+
* @var String
|
144 |
+
* @access private
|
145 |
+
*/
|
146 |
+
var $decryptIV = "\0\0\0\0\0\0\0\0";
|
147 |
+
|
148 |
+
/**
|
149 |
+
* The Crypt_DES objects
|
150 |
+
*
|
151 |
+
* @var Array
|
152 |
+
* @access private
|
153 |
+
*/
|
154 |
+
var $des;
|
155 |
+
|
156 |
+
/**
|
157 |
+
* mcrypt resource for encryption
|
158 |
+
*
|
159 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
160 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
161 |
+
*
|
162 |
+
* @see Crypt_TripleDES::encrypt()
|
163 |
+
* @var String
|
164 |
+
* @access private
|
165 |
+
*/
|
166 |
+
var $enmcrypt;
|
167 |
+
|
168 |
+
/**
|
169 |
+
* mcrypt resource for decryption
|
170 |
+
*
|
171 |
+
* The mcrypt resource can be recreated every time something needs to be created or it can be created just once.
|
172 |
+
* Since mcrypt operates in continuous mode, by default, it'll need to be recreated when in non-continuous mode.
|
173 |
+
*
|
174 |
+
* @see Crypt_TripleDES::decrypt()
|
175 |
+
* @var String
|
176 |
+
* @access private
|
177 |
+
*/
|
178 |
+
var $demcrypt;
|
179 |
+
|
180 |
+
/**
|
181 |
+
* Does the enmcrypt resource need to be (re)initialized?
|
182 |
+
*
|
183 |
+
* @see Crypt_TripleDES::setKey()
|
184 |
+
* @see Crypt_TripleDES::setIV()
|
185 |
+
* @var Boolean
|
186 |
+
* @access private
|
187 |
+
*/
|
188 |
+
var $enchanged = true;
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Does the demcrypt resource need to be (re)initialized?
|
192 |
+
*
|
193 |
+
* @see Crypt_TripleDES::setKey()
|
194 |
+
* @see Crypt_TripleDES::setIV()
|
195 |
+
* @var Boolean
|
196 |
+
* @access private
|
197 |
+
*/
|
198 |
+
var $dechanged = true;
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Is the mode one that is paddable?
|
202 |
+
*
|
203 |
+
* @see Crypt_TripleDES::Crypt_TripleDES()
|
204 |
+
* @var Boolean
|
205 |
+
* @access private
|
206 |
+
*/
|
207 |
+
var $paddable = false;
|
208 |
+
|
209 |
+
/**
|
210 |
+
* Encryption buffer for CTR, OFB and CFB modes
|
211 |
+
*
|
212 |
+
* @see Crypt_TripleDES::encrypt()
|
213 |
+
* @var String
|
214 |
+
* @access private
|
215 |
+
*/
|
216 |
+
var $enbuffer = '';
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Decryption buffer for CTR, OFB and CFB modes
|
220 |
+
*
|
221 |
+
* @see Crypt_TripleDES::decrypt()
|
222 |
+
* @var String
|
223 |
+
* @access private
|
224 |
+
*/
|
225 |
+
var $debuffer = '';
|
226 |
+
|
227 |
+
/**
|
228 |
+
* mcrypt resource for CFB mode
|
229 |
+
*
|
230 |
+
* @see Crypt_TripleDES::encrypt()
|
231 |
+
* @see Crypt_TripleDES::decrypt()
|
232 |
+
* @var String
|
233 |
+
* @access private
|
234 |
+
*/
|
235 |
+
var $ecb;
|
236 |
+
|
237 |
+
/**
|
238 |
+
* Default Constructor.
|
239 |
+
*
|
240 |
+
* Determines whether or not the mcrypt extension should be used. $mode should only, at present, be
|
241 |
+
* CRYPT_DES_MODE_ECB or CRYPT_DES_MODE_CBC. If not explictly set, CRYPT_DES_MODE_CBC will be used.
|
242 |
+
*
|
243 |
+
* @param optional Integer $mode
|
244 |
+
* @return Crypt_TripleDES
|
245 |
+
* @access public
|
246 |
+
*/
|
247 |
+
function Crypt_TripleDES($mode = CRYPT_DES_MODE_CBC)
|
248 |
+
{
|
249 |
+
if ( !defined('CRYPT_DES_MODE') ) {
|
250 |
+
switch (true) {
|
251 |
+
case extension_loaded('mcrypt'):
|
252 |
+
// i'd check to see if des was supported, by doing in_array('des', mcrypt_list_algorithms('')),
|
253 |
+
// but since that can be changed after the object has been created, there doesn't seem to be
|
254 |
+
// a lot of point...
|
255 |
+
define('CRYPT_DES_MODE', CRYPT_DES_MODE_MCRYPT);
|
256 |
+
break;
|
257 |
+
default:
|
258 |
+
define('CRYPT_DES_MODE', CRYPT_DES_MODE_INTERNAL);
|
259 |
+
}
|
260 |
+
}
|
261 |
+
|
262 |
+
if ( $mode == CRYPT_DES_MODE_3CBC ) {
|
263 |
+
$this->mode = CRYPT_DES_MODE_3CBC;
|
264 |
+
$this->des = array(
|
265 |
+
new Crypt_DES(CRYPT_DES_MODE_CBC),
|
266 |
+
new Crypt_DES(CRYPT_DES_MODE_CBC),
|
267 |
+
new Crypt_DES(CRYPT_DES_MODE_CBC)
|
268 |
+
);
|
269 |
+
|
270 |
+
// we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
|
271 |
+
$this->des[0]->disablePadding();
|
272 |
+
$this->des[1]->disablePadding();
|
273 |
+
$this->des[2]->disablePadding();
|
274 |
+
|
275 |
+
return;
|
276 |
+
}
|
277 |
+
|
278 |
+
switch ( CRYPT_DES_MODE ) {
|
279 |
+
case CRYPT_DES_MODE_MCRYPT:
|
280 |
+
switch ($mode) {
|
281 |
+
case CRYPT_DES_MODE_ECB:
|
282 |
+
$this->paddable = true;
|
283 |
+
$this->mode = MCRYPT_MODE_ECB;
|
284 |
+
break;
|
285 |
+
case CRYPT_DES_MODE_CTR:
|
286 |
+
$this->mode = 'ctr';
|
287 |
+
break;
|
288 |
+
case CRYPT_DES_MODE_CFB:
|
289 |
+
$this->mode = 'ncfb';
|
290 |
+
break;
|
291 |
+
case CRYPT_DES_MODE_OFB:
|
292 |
+
$this->mode = MCRYPT_MODE_NOFB;
|
293 |
+
break;
|
294 |
+
case CRYPT_DES_MODE_CBC:
|
295 |
+
default:
|
296 |
+
$this->paddable = true;
|
297 |
+
$this->mode = MCRYPT_MODE_CBC;
|
298 |
+
}
|
299 |
+
|
300 |
+
break;
|
301 |
+
default:
|
302 |
+
$this->des = array(
|
303 |
+
new Crypt_DES(CRYPT_DES_MODE_ECB),
|
304 |
+
new Crypt_DES(CRYPT_DES_MODE_ECB),
|
305 |
+
new Crypt_DES(CRYPT_DES_MODE_ECB)
|
306 |
+
);
|
307 |
+
|
308 |
+
// we're going to be doing the padding, ourselves, so disable it in the Crypt_DES objects
|
309 |
+
$this->des[0]->disablePadding();
|
310 |
+
$this->des[1]->disablePadding();
|
311 |
+
$this->des[2]->disablePadding();
|
312 |
+
|
313 |
+
switch ($mode) {
|
314 |
+
case CRYPT_DES_MODE_ECB:
|
315 |
+
case CRYPT_DES_MODE_CBC:
|
316 |
+
$this->paddable = true;
|
317 |
+
$this->mode = $mode;
|
318 |
+
break;
|
319 |
+
case CRYPT_DES_MODE_CTR:
|
320 |
+
case CRYPT_DES_MODE_CFB:
|
321 |
+
case CRYPT_DES_MODE_OFB:
|
322 |
+
$this->mode = $mode;
|
323 |
+
break;
|
324 |
+
default:
|
325 |
+
$this->paddable = true;
|
326 |
+
$this->mode = CRYPT_DES_MODE_CBC;
|
327 |
+
}
|
328 |
+
}
|
329 |
+
}
|
330 |
+
|
331 |
+
/**
|
332 |
+
* Sets the key.
|
333 |
+
*
|
334 |
+
* Keys can be of any length. Triple DES, itself, can use 128-bit (eg. strlen($key) == 16) or
|
335 |
+
* 192-bit (eg. strlen($key) == 24) keys. This function pads and truncates $key as appropriate.
|
336 |
+
*
|
337 |
+
* DES also requires that every eighth bit be a parity bit, however, we'll ignore that.
|
338 |
+
*
|
339 |
+
* If the key is not explicitly set, it'll be assumed to be all zero's.
|
340 |
+
*
|
341 |
+
* @access public
|
342 |
+
* @param String $key
|
343 |
+
*/
|
344 |
+
function setKey($key)
|
345 |
+
{
|
346 |
+
$length = strlen($key);
|
347 |
+
if ($length > 8) {
|
348 |
+
$key = str_pad($key, 24, chr(0));
|
349 |
+
// if $key is between 64 and 128-bits, use the first 64-bits as the last, per this:
|
350 |
+
// http://php.net/function.mcrypt-encrypt#47973
|
351 |
+
//$key = $length <= 16 ? substr_replace($key, substr($key, 0, 8), 16) : substr($key, 0, 24);
|
352 |
+
} else {
|
353 |
+
$key = str_pad($key, 8, chr(0));
|
354 |
+
}
|
355 |
+
$this->key = $key;
|
356 |
+
switch (true) {
|
357 |
+
case CRYPT_DES_MODE == CRYPT_DES_MODE_INTERNAL:
|
358 |
+
case $this->mode == CRYPT_DES_MODE_3CBC:
|
359 |
+
$this->des[0]->setKey(substr($key, 0, 8));
|
360 |
+
$this->des[1]->setKey(substr($key, 8, 8));
|
361 |
+
$this->des[2]->setKey(substr($key, 16, 8));
|
362 |
+
}
|
363 |
+
$this->enchanged = $this->dechanged = true;
|
364 |
+
}
|
365 |
+
|
366 |
+
/**
|
367 |
+
* Sets the initialization vector. (optional)
|
368 |
+
*
|
369 |
+
* SetIV is not required when CRYPT_DES_MODE_ECB is being used. If not explictly set, it'll be assumed
|
370 |
+
* to be all zero's.
|
371 |
+
*
|
372 |
+
* @access public
|
373 |
+
* @param String $iv
|
374 |
+
*/
|
375 |
+
function setIV($iv)
|
376 |
+
{
|
377 |
+
$this->encryptIV = $this->decryptIV = $this->iv = str_pad(substr($iv, 0, 8), 8, chr(0));
|
378 |
+
if ($this->mode == CRYPT_DES_MODE_3CBC) {
|
379 |
+
$this->des[0]->setIV($iv);
|
380 |
+
$this->des[1]->setIV($iv);
|
381 |
+
$this->des[2]->setIV($iv);
|
382 |
+
}
|
383 |
+
$this->enchanged = $this->dechanged = true;
|
384 |
+
}
|
385 |
+
|
386 |
+
/**
|
387 |
+
* Generate CTR XOR encryption key
|
388 |
+
*
|
389 |
+
* Encrypt the output of this and XOR it against the ciphertext / plaintext to get the
|
390 |
+
* plaintext / ciphertext in CTR mode.
|
391 |
+
*
|
392 |
+
* @see Crypt_TripleDES::decrypt()
|
393 |
+
* @see Crypt_TripleDES::encrypt()
|
394 |
+
* @access private
|
395 |
+
* @param Integer $length
|
396 |
+
* @param String $iv
|
397 |
+
*/
|
398 |
+
function _generate_xor($length, &$iv)
|
399 |
+
{
|
400 |
+
$xor = '';
|
401 |
+
$num_blocks = ($length + 7) >> 3;
|
402 |
+
for ($i = 0; $i < $num_blocks; $i++) {
|
403 |
+
$xor.= $iv;
|
404 |
+
for ($j = 4; $j <= 8; $j+=4) {
|
405 |
+
$temp = substr($iv, -$j, 4);
|
406 |
+
switch ($temp) {
|
407 |
+
case "\xFF\xFF\xFF\xFF":
|
408 |
+
$iv = substr_replace($iv, "\x00\x00\x00\x00", -$j, 4);
|
409 |
+
break;
|
410 |
+
case "\x7F\xFF\xFF\xFF":
|
411 |
+
$iv = substr_replace($iv, "\x80\x00\x00\x00", -$j, 4);
|
412 |
+
break 2;
|
413 |
+
default:
|
414 |
+
extract(unpack('Ncount', $temp));
|
415 |
+
$iv = substr_replace($iv, pack('N', $count + 1), -$j, 4);
|
416 |
+
break 2;
|
417 |
+
}
|
418 |
+
}
|
419 |
+
}
|
420 |
+
|
421 |
+
return $xor;
|
422 |
+
}
|
423 |
+
|
424 |
+
/**
|
425 |
+
* Encrypts a message.
|
426 |
+
*
|
427 |
+
* @access public
|
428 |
+
* @param String $plaintext
|
429 |
+
*/
|
430 |
+
function encrypt($plaintext)
|
431 |
+
{
|
432 |
+
if ($this->paddable) {
|
433 |
+
$plaintext = $this->_pad($plaintext);
|
434 |
+
}
|
435 |
+
|
436 |
+
// if the key is smaller then 8, do what we'd normally do
|
437 |
+
if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
|
438 |
+
$ciphertext = $this->des[2]->encrypt($this->des[1]->decrypt($this->des[0]->encrypt($plaintext)));
|
439 |
+
|
440 |
+
return $ciphertext;
|
441 |
+
}
|
442 |
+
|
443 |
+
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
|
444 |
+
if ($this->enchanged) {
|
445 |
+
if (!isset($this->enmcrypt)) {
|
446 |
+
$this->enmcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
|
447 |
+
}
|
448 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
449 |
+
if ($this->mode != 'ncfb') {
|
450 |
+
$this->enchanged = false;
|
451 |
+
}
|
452 |
+
}
|
453 |
+
|
454 |
+
if ($this->mode != 'ncfb') {
|
455 |
+
$ciphertext = mcrypt_generic($this->enmcrypt, $plaintext);
|
456 |
+
} else {
|
457 |
+
if ($this->enchanged) {
|
458 |
+
$this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, '');
|
459 |
+
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
|
460 |
+
$this->enchanged = false;
|
461 |
+
}
|
462 |
+
|
463 |
+
if (strlen($this->enbuffer)) {
|
464 |
+
$ciphertext = $plaintext ^ substr($this->encryptIV, strlen($this->enbuffer));
|
465 |
+
$this->enbuffer.= $ciphertext;
|
466 |
+
if (strlen($this->enbuffer) == 8) {
|
467 |
+
$this->encryptIV = $this->enbuffer;
|
468 |
+
$this->enbuffer = '';
|
469 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
470 |
+
}
|
471 |
+
$plaintext = substr($plaintext, strlen($ciphertext));
|
472 |
+
} else {
|
473 |
+
$ciphertext = '';
|
474 |
+
}
|
475 |
+
|
476 |
+
$last_pos = strlen($plaintext) & 0xFFFFFFF8;
|
477 |
+
$ciphertext.= $last_pos ? mcrypt_generic($this->enmcrypt, substr($plaintext, 0, $last_pos)) : '';
|
478 |
+
|
479 |
+
if (strlen($plaintext) & 0x7) {
|
480 |
+
if (strlen($ciphertext)) {
|
481 |
+
$this->encryptIV = substr($ciphertext, -8);
|
482 |
+
}
|
483 |
+
$this->encryptIV = mcrypt_generic($this->ecb, $this->encryptIV);
|
484 |
+
$this->enbuffer = substr($plaintext, $last_pos) ^ $this->encryptIV;
|
485 |
+
$ciphertext.= $this->enbuffer;
|
486 |
+
}
|
487 |
+
}
|
488 |
+
|
489 |
+
if (!$this->continuousBuffer) {
|
490 |
+
mcrypt_generic_init($this->enmcrypt, $this->key, $this->encryptIV);
|
491 |
+
}
|
492 |
+
|
493 |
+
return $ciphertext;
|
494 |
+
}
|
495 |
+
|
496 |
+
if (strlen($this->key) <= 8) {
|
497 |
+
$this->des[0]->mode = $this->mode;
|
498 |
+
|
499 |
+
return $this->des[0]->encrypt($plaintext);
|
500 |
+
}
|
501 |
+
|
502 |
+
$des = $this->des;
|
503 |
+
|
504 |
+
$buffer = &$this->enbuffer;
|
505 |
+
$continuousBuffer = $this->continuousBuffer;
|
506 |
+
$ciphertext = '';
|
507 |
+
switch ($this->mode) {
|
508 |
+
case CRYPT_DES_MODE_ECB:
|
509 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
510 |
+
$block = substr($plaintext, $i, 8);
|
511 |
+
// all of these _processBlock calls could, in theory, be put in a function - say Crypt_TripleDES::_ede_encrypt() or something.
|
512 |
+
// only problem with that: it would slow encryption and decryption down. $this->des would have to be called every time that
|
513 |
+
// function is called, instead of once for the whole string of text that's being encrypted, which would, in turn, make
|
514 |
+
// encryption and decryption take more time, per this:
|
515 |
+
//
|
516 |
+
// http://blog.libssh2.org/index.php?/archives/21-Compiled-Variables.html
|
517 |
+
$block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
518 |
+
$block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
|
519 |
+
$block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
520 |
+
$ciphertext.= $block;
|
521 |
+
}
|
522 |
+
break;
|
523 |
+
case CRYPT_DES_MODE_CBC:
|
524 |
+
$xor = $this->encryptIV;
|
525 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
526 |
+
$block = substr($plaintext, $i, 8) ^ $xor;
|
527 |
+
$block = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
528 |
+
$block = $des[1]->_processBlock($block, CRYPT_DES_DECRYPT);
|
529 |
+
$block = $des[2]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
530 |
+
$xor = $block;
|
531 |
+
$ciphertext.= $block;
|
532 |
+
}
|
533 |
+
if ($this->continuousBuffer) {
|
534 |
+
$this->encryptIV = $xor;
|
535 |
+
}
|
536 |
+
break;
|
537 |
+
case CRYPT_DES_MODE_CTR:
|
538 |
+
$xor = $this->encryptIV;
|
539 |
+
if (strlen($buffer)) {
|
540 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
541 |
+
$block = substr($plaintext, $i, 8);
|
542 |
+
$key = $this->_generate_xor(8, $xor);
|
543 |
+
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
544 |
+
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
|
545 |
+
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
546 |
+
$buffer.= $key;
|
547 |
+
$key = $this->_string_shift($buffer, 8);
|
548 |
+
$ciphertext.= $block ^ $key;
|
549 |
+
}
|
550 |
+
} else {
|
551 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
552 |
+
$block = substr($plaintext, $i, 8);
|
553 |
+
$key = $this->_generate_xor(8, $xor);
|
554 |
+
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
555 |
+
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
|
556 |
+
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
557 |
+
$ciphertext.= $block ^ $key;
|
558 |
+
}
|
559 |
+
}
|
560 |
+
if ($this->continuousBuffer) {
|
561 |
+
$this->encryptIV = $xor;
|
562 |
+
if ($start = strlen($plaintext) & 7) {
|
563 |
+
$buffer = substr($key, $start) . $buffer;
|
564 |
+
}
|
565 |
+
}
|
566 |
+
break;
|
567 |
+
case CRYPT_DES_MODE_CFB:
|
568 |
+
if (!empty($buffer['xor'])) {
|
569 |
+
$ciphertext = $plaintext ^ $buffer['xor'];
|
570 |
+
$iv = $buffer['encrypted'] . $ciphertext;
|
571 |
+
$start = strlen($ciphertext);
|
572 |
+
$buffer['encrypted'].= $ciphertext;
|
573 |
+
$buffer['xor'] = substr($buffer['xor'], strlen($ciphertext));
|
574 |
+
} else {
|
575 |
+
$ciphertext = '';
|
576 |
+
$iv = $this->encryptIV;
|
577 |
+
$start = 0;
|
578 |
+
}
|
579 |
+
|
580 |
+
for ($i = $start; $i < strlen($plaintext); $i+=8) {
|
581 |
+
$block = substr($plaintext, $i, 8);
|
582 |
+
$iv = $des[0]->_processBlock($iv, CRYPT_DES_ENCRYPT);
|
583 |
+
$iv = $des[1]->_processBlock($iv, CRYPT_DES_DECRYPT);
|
584 |
+
$xor= $des[2]->_processBlock($iv, CRYPT_DES_ENCRYPT);
|
585 |
+
|
586 |
+
$iv = $block ^ $xor;
|
587 |
+
if ($continuousBuffer && strlen($iv) != 8) {
|
588 |
+
$buffer = array(
|
589 |
+
'encrypted' => $iv,
|
590 |
+
'xor' => substr($xor, strlen($iv))
|
591 |
+
);
|
592 |
+
}
|
593 |
+
$ciphertext.= $iv;
|
594 |
+
}
|
595 |
+
|
596 |
+
if ($this->continuousBuffer) {
|
597 |
+
$this->encryptIV = $iv;
|
598 |
+
}
|
599 |
+
break;
|
600 |
+
case CRYPT_DES_MODE_OFB:
|
601 |
+
$xor = $this->encryptIV;
|
602 |
+
if (strlen($buffer)) {
|
603 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
604 |
+
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
605 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
606 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
607 |
+
$buffer.= $xor;
|
608 |
+
$key = $this->_string_shift($buffer, 8);
|
609 |
+
$ciphertext.= substr($plaintext, $i, 8) ^ $key;
|
610 |
+
}
|
611 |
+
} else {
|
612 |
+
for ($i = 0; $i < strlen($plaintext); $i+=8) {
|
613 |
+
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
614 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
615 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
616 |
+
$ciphertext.= substr($plaintext, $i, 8) ^ $xor;
|
617 |
+
}
|
618 |
+
$key = $xor;
|
619 |
+
}
|
620 |
+
if ($this->continuousBuffer) {
|
621 |
+
$this->encryptIV = $xor;
|
622 |
+
if ($start = strlen($plaintext) & 7) {
|
623 |
+
$buffer = substr($key, $start) . $buffer;
|
624 |
+
}
|
625 |
+
}
|
626 |
+
}
|
627 |
+
|
628 |
+
return $ciphertext;
|
629 |
+
}
|
630 |
+
|
631 |
+
/**
|
632 |
+
* Decrypts a message.
|
633 |
+
*
|
634 |
+
* @access public
|
635 |
+
* @param String $ciphertext
|
636 |
+
*/
|
637 |
+
function decrypt($ciphertext)
|
638 |
+
{
|
639 |
+
if ($this->mode == CRYPT_DES_MODE_3CBC && strlen($this->key) > 8) {
|
640 |
+
$plaintext = $this->des[0]->decrypt($this->des[1]->encrypt($this->des[2]->decrypt($ciphertext)));
|
641 |
+
|
642 |
+
return $this->_unpad($plaintext);
|
643 |
+
}
|
644 |
+
|
645 |
+
if ($this->paddable) {
|
646 |
+
// we pad with chr(0) since that's what mcrypt_generic does. to quote from http://php.net/function.mcrypt-generic :
|
647 |
+
// "The data is padded with "\0" to make sure the length of the data is n * blocksize."
|
648 |
+
$ciphertext = str_pad($ciphertext, (strlen($ciphertext) + 7) & 0xFFFFFFF8, chr(0));
|
649 |
+
}
|
650 |
+
|
651 |
+
if ( CRYPT_DES_MODE == CRYPT_DES_MODE_MCRYPT ) {
|
652 |
+
if ($this->dechanged) {
|
653 |
+
if (!isset($this->demcrypt)) {
|
654 |
+
$this->demcrypt = mcrypt_module_open(MCRYPT_3DES, '', $this->mode, '');
|
655 |
+
}
|
656 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
657 |
+
if ($this->mode != 'ncfb') {
|
658 |
+
$this->dechanged = false;
|
659 |
+
}
|
660 |
+
}
|
661 |
+
|
662 |
+
if ($this->mode != 'ncfb') {
|
663 |
+
$plaintext = mdecrypt_generic($this->demcrypt, $ciphertext);
|
664 |
+
} else {
|
665 |
+
if ($this->dechanged) {
|
666 |
+
$this->ecb = mcrypt_module_open(MCRYPT_3DES, '', MCRYPT_MODE_ECB, '');
|
667 |
+
mcrypt_generic_init($this->ecb, $this->key, "\0\0\0\0\0\0\0\0");
|
668 |
+
$this->dechanged = false;
|
669 |
+
}
|
670 |
+
|
671 |
+
if (strlen($this->debuffer)) {
|
672 |
+
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($this->debuffer));
|
673 |
+
|
674 |
+
$this->debuffer.= substr($ciphertext, 0, strlen($plaintext));
|
675 |
+
if (strlen($this->debuffer) == 8) {
|
676 |
+
$this->decryptIV = $this->debuffer;
|
677 |
+
$this->debuffer = '';
|
678 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
679 |
+
}
|
680 |
+
$ciphertext = substr($ciphertext, strlen($plaintext));
|
681 |
+
} else {
|
682 |
+
$plaintext = '';
|
683 |
+
}
|
684 |
+
|
685 |
+
$last_pos = strlen($ciphertext) & 0xFFFFFFF8;
|
686 |
+
$plaintext.= $last_pos ? mdecrypt_generic($this->demcrypt, substr($ciphertext, 0, $last_pos)) : '';
|
687 |
+
|
688 |
+
if (strlen($ciphertext) & 0x7) {
|
689 |
+
if (strlen($plaintext)) {
|
690 |
+
$this->decryptIV = substr($ciphertext, $last_pos - 8, 8);
|
691 |
+
}
|
692 |
+
$this->decryptIV = mcrypt_generic($this->ecb, $this->decryptIV);
|
693 |
+
$this->debuffer = substr($ciphertext, $last_pos);
|
694 |
+
$plaintext.= $this->debuffer ^ $this->decryptIV;
|
695 |
+
}
|
696 |
+
|
697 |
+
return $plaintext;
|
698 |
+
}
|
699 |
+
|
700 |
+
if (!$this->continuousBuffer) {
|
701 |
+
mcrypt_generic_init($this->demcrypt, $this->key, $this->decryptIV);
|
702 |
+
}
|
703 |
+
|
704 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
705 |
+
}
|
706 |
+
|
707 |
+
if (strlen($this->key) <= 8) {
|
708 |
+
$this->des[0]->mode = $this->mode;
|
709 |
+
$plaintext = $this->des[0]->decrypt($ciphertext);
|
710 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
711 |
+
}
|
712 |
+
|
713 |
+
$des = $this->des;
|
714 |
+
|
715 |
+
$buffer = &$this->enbuffer;
|
716 |
+
$continuousBuffer = $this->continuousBuffer;
|
717 |
+
$plaintext = '';
|
718 |
+
switch ($this->mode) {
|
719 |
+
case CRYPT_DES_MODE_ECB:
|
720 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
721 |
+
$block = substr($ciphertext, $i, 8);
|
722 |
+
$block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
|
723 |
+
$block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
724 |
+
$block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
|
725 |
+
$plaintext.= $block;
|
726 |
+
}
|
727 |
+
break;
|
728 |
+
case CRYPT_DES_MODE_CBC:
|
729 |
+
$xor = $this->decryptIV;
|
730 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
731 |
+
$orig = $block = substr($ciphertext, $i, 8);
|
732 |
+
$block = $des[2]->_processBlock($block, CRYPT_DES_DECRYPT);
|
733 |
+
$block = $des[1]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
734 |
+
$block = $des[0]->_processBlock($block, CRYPT_DES_DECRYPT);
|
735 |
+
$plaintext.= $block ^ $xor;
|
736 |
+
$xor = $orig;
|
737 |
+
}
|
738 |
+
if ($this->continuousBuffer) {
|
739 |
+
$this->decryptIV = $xor;
|
740 |
+
}
|
741 |
+
break;
|
742 |
+
case CRYPT_DES_MODE_CTR:
|
743 |
+
$xor = $this->decryptIV;
|
744 |
+
if (strlen($buffer)) {
|
745 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
746 |
+
$block = substr($ciphertext, $i, 8);
|
747 |
+
$key = $this->_generate_xor(8, $xor);
|
748 |
+
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
749 |
+
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
|
750 |
+
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
751 |
+
$buffer.= $key;
|
752 |
+
$key = $this->_string_shift($buffer, 8);
|
753 |
+
$plaintext.= $block ^ $key;
|
754 |
+
}
|
755 |
+
} else {
|
756 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
757 |
+
$block = substr($ciphertext, $i, 8);
|
758 |
+
$key = $this->_generate_xor(8, $xor);
|
759 |
+
$key = $des[0]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
760 |
+
$key = $des[1]->_processBlock($key, CRYPT_DES_DECRYPT);
|
761 |
+
$key = $des[2]->_processBlock($key, CRYPT_DES_ENCRYPT);
|
762 |
+
$plaintext.= $block ^ $key;
|
763 |
+
}
|
764 |
+
}
|
765 |
+
if ($this->continuousBuffer) {
|
766 |
+
$this->decryptIV = $xor;
|
767 |
+
if ($start = strlen($plaintext) & 7) {
|
768 |
+
$buffer = substr($key, $start) . $buffer;
|
769 |
+
}
|
770 |
+
}
|
771 |
+
break;
|
772 |
+
case CRYPT_DES_MODE_CFB:
|
773 |
+
if (!empty($buffer['ciphertext'])) {
|
774 |
+
$plaintext = $ciphertext ^ substr($this->decryptIV, strlen($buffer['ciphertext']));
|
775 |
+
$buffer['ciphertext'].= substr($ciphertext, 0, strlen($plaintext));
|
776 |
+
if (strlen($buffer['ciphertext']) == 8) {
|
777 |
+
$xor = $des[0]->_processBlock($buffer['ciphertext'], CRYPT_DES_ENCRYPT);
|
778 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
779 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
780 |
+
$buffer['ciphertext'] = '';
|
781 |
+
}
|
782 |
+
$start = strlen($plaintext);
|
783 |
+
$block = $this->decryptIV;
|
784 |
+
} else {
|
785 |
+
$plaintext = '';
|
786 |
+
$xor = $des[0]->_processBlock($this->decryptIV, CRYPT_DES_ENCRYPT);
|
787 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
788 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
789 |
+
$start = 0;
|
790 |
+
}
|
791 |
+
|
792 |
+
for ($i = $start; $i < strlen($ciphertext); $i+=8) {
|
793 |
+
$block = substr($ciphertext, $i, 8);
|
794 |
+
$plaintext.= $block ^ $xor;
|
795 |
+
if ($continuousBuffer && strlen($block) != 8) {
|
796 |
+
$buffer['ciphertext'].= $block;
|
797 |
+
$block = $xor;
|
798 |
+
} else if (strlen($block) == 8) {
|
799 |
+
$xor = $des[0]->_processBlock($block, CRYPT_DES_ENCRYPT);
|
800 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
801 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
802 |
+
}
|
803 |
+
}
|
804 |
+
if ($this->continuousBuffer) {
|
805 |
+
$this->decryptIV = $block;
|
806 |
+
}
|
807 |
+
break;
|
808 |
+
case CRYPT_DES_MODE_OFB:
|
809 |
+
$xor = $this->decryptIV;
|
810 |
+
if (strlen($buffer)) {
|
811 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
812 |
+
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
813 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
814 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
815 |
+
$buffer.= $xor;
|
816 |
+
$key = $this->_string_shift($buffer, 8);
|
817 |
+
$plaintext.= substr($ciphertext, $i, 8) ^ $key;
|
818 |
+
}
|
819 |
+
} else {
|
820 |
+
for ($i = 0; $i < strlen($ciphertext); $i+=8) {
|
821 |
+
$xor = $des[0]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
822 |
+
$xor = $des[1]->_processBlock($xor, CRYPT_DES_DECRYPT);
|
823 |
+
$xor = $des[2]->_processBlock($xor, CRYPT_DES_ENCRYPT);
|
824 |
+
$plaintext.= substr($ciphertext, $i, 8) ^ $xor;
|
825 |
+
}
|
826 |
+
$key = $xor;
|
827 |
+
}
|
828 |
+
if ($this->continuousBuffer) {
|
829 |
+
$this->decryptIV = $xor;
|
830 |
+
if ($start = strlen($ciphertext) & 7) {
|
831 |
+
$buffer = substr($key, $start) . $buffer;
|
832 |
+
}
|
833 |
+
}
|
834 |
+
}
|
835 |
+
|
836 |
+
return $this->paddable ? $this->_unpad($plaintext) : $plaintext;
|
837 |
+
}
|
838 |
+
|
839 |
+
/**
|
840 |
+
* Treat consecutive "packets" as if they are a continuous buffer.
|
841 |
+
*
|
842 |
+
* Say you have a 16-byte plaintext $plaintext. Using the default behavior, the two following code snippets
|
843 |
+
* will yield different outputs:
|
844 |
+
*
|
845 |
+
* <code>
|
846 |
+
* echo $des->encrypt(substr($plaintext, 0, 8));
|
847 |
+
* echo $des->encrypt(substr($plaintext, 8, 8));
|
848 |
+
* </code>
|
849 |
+
* <code>
|
850 |
+
* echo $des->encrypt($plaintext);
|
851 |
+
* </code>
|
852 |
+
*
|
853 |
+
* The solution is to enable the continuous buffer. Although this will resolve the above discrepancy, it creates
|
854 |
+
* another, as demonstrated with the following:
|
855 |
+
*
|
856 |
+
* <code>
|
857 |
+
* $des->encrypt(substr($plaintext, 0, 8));
|
858 |
+
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
859 |
+
* </code>
|
860 |
+
* <code>
|
861 |
+
* echo $des->decrypt($des->encrypt(substr($plaintext, 8, 8)));
|
862 |
+
* </code>
|
863 |
+
*
|
864 |
+
* With the continuous buffer disabled, these would yield the same output. With it enabled, they yield different
|
865 |
+
* outputs. The reason is due to the fact that the initialization vector's change after every encryption /
|
866 |
+
* decryption round when the continuous buffer is enabled. When it's disabled, they remain constant.
|
867 |
+
*
|
868 |
+
* Put another way, when the continuous buffer is enabled, the state of the Crypt_DES() object changes after each
|
869 |
+
* encryption / decryption round, whereas otherwise, it'd remain constant. For this reason, it's recommended that
|
870 |
+
* continuous buffers not be used. They do offer better security and are, in fact, sometimes required (SSH uses them),
|
871 |
+
* however, they are also less intuitive and more likely to cause you problems.
|
872 |
+
*
|
873 |
+
* @see Crypt_TripleDES::disableContinuousBuffer()
|
874 |
+
* @access public
|
875 |
+
*/
|
876 |
+
function enableContinuousBuffer()
|
877 |
+
{
|
878 |
+
$this->continuousBuffer = true;
|
879 |
+
if ($this->mode == CRYPT_DES_MODE_3CBC) {
|
880 |
+
$this->des[0]->enableContinuousBuffer();
|
881 |
+
$this->des[1]->enableContinuousBuffer();
|
882 |
+
$this->des[2]->enableContinuousBuffer();
|
883 |
+
}
|
884 |
+
}
|
885 |
+
|
886 |
+
/**
|
887 |
+
* Treat consecutive packets as if they are a discontinuous buffer.
|
888 |
+
*
|
889 |
+
* The default behavior.
|
890 |
+
*
|
891 |
+
* @see Crypt_TripleDES::enableContinuousBuffer()
|
892 |
+
* @access public
|
893 |
+
*/
|
894 |
+
function disableContinuousBuffer()
|
895 |
+
{
|
896 |
+
$this->continuousBuffer = false;
|
897 |
+
$this->encryptIV = $this->iv;
|
898 |
+
$this->decryptIV = $this->iv;
|
899 |
+
|
900 |
+
if ($this->mode == CRYPT_DES_MODE_3CBC) {
|
901 |
+
$this->des[0]->disableContinuousBuffer();
|
902 |
+
$this->des[1]->disableContinuousBuffer();
|
903 |
+
$this->des[2]->disableContinuousBuffer();
|
904 |
+
}
|
905 |
+
}
|
906 |
+
|
907 |
+
/**
|
908 |
+
* Pad "packets".
|
909 |
+
*
|
910 |
+
* DES works by encrypting eight bytes at a time. If you ever need to encrypt or decrypt something that's not
|
911 |
+
* a multiple of eight, it becomes necessary to pad the input so that it's length is a multiple of eight.
|
912 |
+
*
|
913 |
+
* Padding is enabled by default. Sometimes, however, it is undesirable to pad strings. Such is the case in SSH1,
|
914 |
+
* where "packets" are padded with random bytes before being encrypted. Unpad these packets and you risk stripping
|
915 |
+
* away characters that shouldn't be stripped away. (SSH knows how many bytes are added because the length is
|
916 |
+
* transmitted separately)
|
917 |
+
*
|
918 |
+
* @see Crypt_TripleDES::disablePadding()
|
919 |
+
* @access public
|
920 |
+
*/
|
921 |
+
function enablePadding()
|
922 |
+
{
|
923 |
+
$this->padding = true;
|
924 |
+
}
|
925 |
+
|
926 |
+
/**
|
927 |
+
* Do not pad packets.
|
928 |
+
*
|
929 |
+
* @see Crypt_TripleDES::enablePadding()
|
930 |
+
* @access public
|
931 |
+
*/
|
932 |
+
function disablePadding()
|
933 |
+
{
|
934 |
+
$this->padding = false;
|
935 |
+
}
|
936 |
+
|
937 |
+
/**
|
938 |
+
* Pads a string
|
939 |
+
*
|
940 |
+
* Pads a string using the RSA PKCS padding standards so that its length is a multiple of the blocksize (8).
|
941 |
+
* 8 - (strlen($text) & 7) bytes are added, each of which is equal to chr(8 - (strlen($text) & 7)
|
942 |
+
*
|
943 |
+
* If padding is disabled and $text is not a multiple of the blocksize, the string will be padded regardless
|
944 |
+
* and padding will, hence forth, be enabled.
|
945 |
+
*
|
946 |
+
* @see Crypt_TripleDES::_unpad()
|
947 |
+
* @access private
|
948 |
+
*/
|
949 |
+
function _pad($text)
|
950 |
+
{
|
951 |
+
$length = strlen($text);
|
952 |
+
|
953 |
+
if (!$this->padding) {
|
954 |
+
if (($length & 7) == 0) {
|
955 |
+
return $text;
|
956 |
+
} else {
|
957 |
+
user_error("The plaintext's length ($length) is not a multiple of the block size (8)", E_USER_NOTICE);
|
958 |
+
$this->padding = true;
|
959 |
+
}
|
960 |
+
}
|
961 |
+
|
962 |
+
$pad = 8 - ($length & 7);
|
963 |
+
return str_pad($text, $length + $pad, chr($pad));
|
964 |
+
}
|
965 |
+
|
966 |
+
/**
|
967 |
+
* Unpads a string
|
968 |
+
*
|
969 |
+
* If padding is enabled and the reported padding length is invalid the encryption key will be assumed to be wrong
|
970 |
+
* and false will be returned.
|
971 |
+
*
|
972 |
+
* @see Crypt_TripleDES::_pad()
|
973 |
+
* @access private
|
974 |
+
*/
|
975 |
+
function _unpad($text)
|
976 |
+
{
|
977 |
+
if (!$this->padding) {
|
978 |
+
return $text;
|
979 |
+
}
|
980 |
+
|
981 |
+
$length = ord($text[strlen($text) - 1]);
|
982 |
+
|
983 |
+
if (!$length || $length > 8) {
|
984 |
+
return false;
|
985 |
+
}
|
986 |
+
|
987 |
+
return substr($text, 0, -$length);
|
988 |
+
}
|
989 |
+
|
990 |
+
/**
|
991 |
+
* String Shift
|
992 |
+
*
|
993 |
+
* Inspired by array_shift
|
994 |
+
*
|
995 |
+
* @param String $string
|
996 |
+
* @param optional Integer $index
|
997 |
+
* @return String
|
998 |
+
* @access private
|
999 |
+
*/
|
1000 |
+
function _string_shift(&$string, $index = 1)
|
1001 |
+
{
|
1002 |
+
$substr = substr($string, 0, $index);
|
1003 |
+
$string = substr($string, $index);
|
1004 |
+
return $substr;
|
1005 |
+
}
|
1006 |
+
}
|
1007 |
+
|
1008 |
+
// vim: ts=4:sw=4:et:
|
1009 |
+
// vim6: fdl=1:
|
classes/phpseclib/Math/BigInteger.php
ADDED
@@ -0,0 +1,3551 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP arbitrary precision integer arithmetic library.
|
6 |
+
*
|
7 |
+
* Supports base-2, base-10, base-16, and base-256 numbers. Uses the GMP or BCMath extensions, if available,
|
8 |
+
* and an internal implementation, otherwise.
|
9 |
+
*
|
10 |
+
* PHP versions 4 and 5
|
11 |
+
*
|
12 |
+
* {@internal (all DocBlock comments regarding implementation - such as the one that follows - refer to the
|
13 |
+
* {@link MATH_BIGINTEGER_MODE_INTERNAL MATH_BIGINTEGER_MODE_INTERNAL} mode)
|
14 |
+
*
|
15 |
+
* Math_BigInteger uses base-2**26 to perform operations such as multiplication and division and
|
16 |
+
* base-2**52 (ie. two base 2**26 digits) to perform addition and subtraction. Because the largest possible
|
17 |
+
* value when multiplying two base-2**26 numbers together is a base-2**52 number, double precision floating
|
18 |
+
* point numbers - numbers that should be supported on most hardware and whose significand is 53 bits - are
|
19 |
+
* used. As a consequence, bitwise operators such as >> and << cannot be used, nor can the modulo operator %,
|
20 |
+
* which only supports integers. Although this fact will slow this library down, the fact that such a high
|
21 |
+
* base is being used should more than compensate.
|
22 |
+
*
|
23 |
+
* When PHP version 6 is officially released, we'll be able to use 64-bit integers. This should, once again,
|
24 |
+
* allow bitwise operators, and will increase the maximum possible base to 2**31 (or 2**62 for addition /
|
25 |
+
* subtraction).
|
26 |
+
*
|
27 |
+
* Numbers are stored in {@link http://en.wikipedia.org/wiki/Endianness little endian} format. ie.
|
28 |
+
* (new Math_BigInteger(pow(2, 26)))->value = array(0, 1)
|
29 |
+
*
|
30 |
+
* Useful resources are as follows:
|
31 |
+
*
|
32 |
+
* - {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf Handbook of Applied Cryptography (HAC)}
|
33 |
+
* - {@link http://math.libtomcrypt.com/files/tommath.pdf Multi-Precision Math (MPM)}
|
34 |
+
* - Java's BigInteger classes. See /j2se/src/share/classes/java/math in jdk-1_5_0-src-jrl.zip
|
35 |
+
*
|
36 |
+
* Here's an example of how to use this library:
|
37 |
+
* <code>
|
38 |
+
* <?php
|
39 |
+
* include('Math/BigInteger.php');
|
40 |
+
*
|
41 |
+
* $a = new Math_BigInteger(2);
|
42 |
+
* $b = new Math_BigInteger(3);
|
43 |
+
*
|
44 |
+
* $c = $a->add($b);
|
45 |
+
*
|
46 |
+
* echo $c->toString(); // outputs 5
|
47 |
+
* ?>
|
48 |
+
* </code>
|
49 |
+
*
|
50 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
51 |
+
* of this software and associated documentation files (the "Software"), to deal
|
52 |
+
* in the Software without restriction, including without limitation the rights
|
53 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
54 |
+
* copies of the Software, and to permit persons to whom the Software is
|
55 |
+
* furnished to do so, subject to the following conditions:
|
56 |
+
*
|
57 |
+
* The above copyright notice and this permission notice shall be included in
|
58 |
+
* all copies or substantial portions of the Software.
|
59 |
+
*
|
60 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
61 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
62 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
63 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
64 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
65 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
66 |
+
* THE SOFTWARE.
|
67 |
+
*
|
68 |
+
* @category Math
|
69 |
+
* @package Math_BigInteger
|
70 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
71 |
+
* @copyright MMVI Jim Wigginton
|
72 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
73 |
+
* @version $Id: BigInteger.php,v 1.33 2010/03/22 22:32:03 terrafrost Exp $
|
74 |
+
* @link http://pear.php.net/package/Math_BigInteger
|
75 |
+
*/
|
76 |
+
|
77 |
+
/**#@+
|
78 |
+
* Reduction constants
|
79 |
+
*
|
80 |
+
* @access private
|
81 |
+
* @see Math_BigInteger::_reduce()
|
82 |
+
*/
|
83 |
+
/**
|
84 |
+
* @see Math_BigInteger::_montgomery()
|
85 |
+
* @see Math_BigInteger::_prepMontgomery()
|
86 |
+
*/
|
87 |
+
define('MATH_BIGINTEGER_MONTGOMERY', 0);
|
88 |
+
/**
|
89 |
+
* @see Math_BigInteger::_barrett()
|
90 |
+
*/
|
91 |
+
define('MATH_BIGINTEGER_BARRETT', 1);
|
92 |
+
/**
|
93 |
+
* @see Math_BigInteger::_mod2()
|
94 |
+
*/
|
95 |
+
define('MATH_BIGINTEGER_POWEROF2', 2);
|
96 |
+
/**
|
97 |
+
* @see Math_BigInteger::_remainder()
|
98 |
+
*/
|
99 |
+
define('MATH_BIGINTEGER_CLASSIC', 3);
|
100 |
+
/**
|
101 |
+
* @see Math_BigInteger::__clone()
|
102 |
+
*/
|
103 |
+
define('MATH_BIGINTEGER_NONE', 4);
|
104 |
+
/**#@-*/
|
105 |
+
|
106 |
+
/**#@+
|
107 |
+
* Array constants
|
108 |
+
*
|
109 |
+
* Rather than create a thousands and thousands of new Math_BigInteger objects in repeated function calls to add() and
|
110 |
+
* multiply() or whatever, we'll just work directly on arrays, taking them in as parameters and returning them.
|
111 |
+
*
|
112 |
+
* @access private
|
113 |
+
*/
|
114 |
+
/**
|
115 |
+
* $result[MATH_BIGINTEGER_VALUE] contains the value.
|
116 |
+
*/
|
117 |
+
define('MATH_BIGINTEGER_VALUE', 0);
|
118 |
+
/**
|
119 |
+
* $result[MATH_BIGINTEGER_SIGN] contains the sign.
|
120 |
+
*/
|
121 |
+
define('MATH_BIGINTEGER_SIGN', 1);
|
122 |
+
/**#@-*/
|
123 |
+
|
124 |
+
/**#@+
|
125 |
+
* @access private
|
126 |
+
* @see Math_BigInteger::_montgomery()
|
127 |
+
* @see Math_BigInteger::_barrett()
|
128 |
+
*/
|
129 |
+
/**
|
130 |
+
* Cache constants
|
131 |
+
*
|
132 |
+
* $cache[MATH_BIGINTEGER_VARIABLE] tells us whether or not the cached data is still valid.
|
133 |
+
*/
|
134 |
+
define('MATH_BIGINTEGER_VARIABLE', 0);
|
135 |
+
/**
|
136 |
+
* $cache[MATH_BIGINTEGER_DATA] contains the cached data.
|
137 |
+
*/
|
138 |
+
define('MATH_BIGINTEGER_DATA', 1);
|
139 |
+
/**#@-*/
|
140 |
+
|
141 |
+
/**#@+
|
142 |
+
* Mode constants.
|
143 |
+
*
|
144 |
+
* @access private
|
145 |
+
* @see Math_BigInteger::Math_BigInteger()
|
146 |
+
*/
|
147 |
+
/**
|
148 |
+
* To use the pure-PHP implementation
|
149 |
+
*/
|
150 |
+
define('MATH_BIGINTEGER_MODE_INTERNAL', 1);
|
151 |
+
/**
|
152 |
+
* To use the BCMath library
|
153 |
+
*
|
154 |
+
* (if enabled; otherwise, the internal implementation will be used)
|
155 |
+
*/
|
156 |
+
define('MATH_BIGINTEGER_MODE_BCMATH', 2);
|
157 |
+
/**
|
158 |
+
* To use the GMP library
|
159 |
+
*
|
160 |
+
* (if present; otherwise, either the BCMath or the internal implementation will be used)
|
161 |
+
*/
|
162 |
+
define('MATH_BIGINTEGER_MODE_GMP', 3);
|
163 |
+
/**#@-*/
|
164 |
+
|
165 |
+
/**
|
166 |
+
* The largest digit that may be used in addition / subtraction
|
167 |
+
*
|
168 |
+
* (we do pow(2, 52) instead of using 4503599627370496, directly, because some PHP installations
|
169 |
+
* will truncate 4503599627370496)
|
170 |
+
*
|
171 |
+
* @access private
|
172 |
+
*/
|
173 |
+
define('MATH_BIGINTEGER_MAX_DIGIT52', pow(2, 52));
|
174 |
+
|
175 |
+
/**
|
176 |
+
* Karatsuba Cutoff
|
177 |
+
*
|
178 |
+
* At what point do we switch between Karatsuba multiplication and schoolbook long multiplication?
|
179 |
+
*
|
180 |
+
* @access private
|
181 |
+
*/
|
182 |
+
define('MATH_BIGINTEGER_KARATSUBA_CUTOFF', 25);
|
183 |
+
|
184 |
+
/**
|
185 |
+
* Pure-PHP arbitrary precision integer arithmetic library. Supports base-2, base-10, base-16, and base-256
|
186 |
+
* numbers.
|
187 |
+
*
|
188 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
189 |
+
* @version 1.0.0RC4
|
190 |
+
* @access public
|
191 |
+
* @package Math_BigInteger
|
192 |
+
*/
|
193 |
+
class Math_BigInteger {
|
194 |
+
/**
|
195 |
+
* Holds the BigInteger's value.
|
196 |
+
*
|
197 |
+
* @var Array
|
198 |
+
* @access private
|
199 |
+
*/
|
200 |
+
var $value;
|
201 |
+
|
202 |
+
/**
|
203 |
+
* Holds the BigInteger's magnitude.
|
204 |
+
*
|
205 |
+
* @var Boolean
|
206 |
+
* @access private
|
207 |
+
*/
|
208 |
+
var $is_negative = false;
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Random number generator function
|
212 |
+
*
|
213 |
+
* @see setRandomGenerator()
|
214 |
+
* @access private
|
215 |
+
*/
|
216 |
+
var $generator = 'mt_rand';
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Precision
|
220 |
+
*
|
221 |
+
* @see setPrecision()
|
222 |
+
* @access private
|
223 |
+
*/
|
224 |
+
var $precision = -1;
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Precision Bitmask
|
228 |
+
*
|
229 |
+
* @see setPrecision()
|
230 |
+
* @access private
|
231 |
+
*/
|
232 |
+
var $bitmask = false;
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Mode independant value used for serialization.
|
236 |
+
*
|
237 |
+
* If the bcmath or gmp extensions are installed $this->value will be a non-serializable resource, hence the need for
|
238 |
+
* a variable that'll be serializable regardless of whether or not extensions are being used. Unlike $this->value,
|
239 |
+
* however, $this->hex is only calculated when $this->__sleep() is called.
|
240 |
+
*
|
241 |
+
* @see __sleep()
|
242 |
+
* @see __wakeup()
|
243 |
+
* @var String
|
244 |
+
* @access private
|
245 |
+
*/
|
246 |
+
var $hex;
|
247 |
+
|
248 |
+
/**
|
249 |
+
* Converts base-2, base-10, base-16, and binary strings (eg. base-256) to BigIntegers.
|
250 |
+
*
|
251 |
+
* If the second parameter - $base - is negative, then it will be assumed that the number's are encoded using
|
252 |
+
* two's compliment. The sole exception to this is -10, which is treated the same as 10 is.
|
253 |
+
*
|
254 |
+
* Here's an example:
|
255 |
+
* <code>
|
256 |
+
* <?php
|
257 |
+
* include('Math/BigInteger.php');
|
258 |
+
*
|
259 |
+
* $a = new Math_BigInteger('0x32', 16); // 50 in base-16
|
260 |
+
*
|
261 |
+
* echo $a->toString(); // outputs 50
|
262 |
+
* ?>
|
263 |
+
* </code>
|
264 |
+
*
|
265 |
+
* @param optional $x base-10 number or base-$base number if $base set.
|
266 |
+
* @param optional integer $base
|
267 |
+
* @return Math_BigInteger
|
268 |
+
* @access public
|
269 |
+
*/
|
270 |
+
function Math_BigInteger($x = 0, $base = 10)
|
271 |
+
{
|
272 |
+
if ( !defined('MATH_BIGINTEGER_MODE') ) {
|
273 |
+
switch (true) {
|
274 |
+
case extension_loaded('gmp'):
|
275 |
+
define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_GMP);
|
276 |
+
break;
|
277 |
+
case extension_loaded('bcmath'):
|
278 |
+
define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_BCMATH);
|
279 |
+
break;
|
280 |
+
default:
|
281 |
+
define('MATH_BIGINTEGER_MODE', MATH_BIGINTEGER_MODE_INTERNAL);
|
282 |
+
}
|
283 |
+
}
|
284 |
+
|
285 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
286 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
287 |
+
if (is_resource($x) && get_resource_type($x) == 'GMP integer') {
|
288 |
+
$this->value = $x;
|
289 |
+
return;
|
290 |
+
}
|
291 |
+
$this->value = gmp_init(0);
|
292 |
+
break;
|
293 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
294 |
+
$this->value = '0';
|
295 |
+
break;
|
296 |
+
default:
|
297 |
+
$this->value = array();
|
298 |
+
}
|
299 |
+
|
300 |
+
if (empty($x)) {
|
301 |
+
return;
|
302 |
+
}
|
303 |
+
|
304 |
+
switch ($base) {
|
305 |
+
case -256:
|
306 |
+
if (ord($x[0]) & 0x80) {
|
307 |
+
$x = ~$x;
|
308 |
+
$this->is_negative = true;
|
309 |
+
}
|
310 |
+
case 256:
|
311 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
312 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
313 |
+
$sign = $this->is_negative ? '-' : '';
|
314 |
+
$this->value = gmp_init($sign . '0x' . bin2hex($x));
|
315 |
+
break;
|
316 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
317 |
+
// round $len to the nearest 4 (thanks, DavidMJ!)
|
318 |
+
$len = (strlen($x) + 3) & 0xFFFFFFFC;
|
319 |
+
|
320 |
+
$x = str_pad($x, $len, chr(0), STR_PAD_LEFT);
|
321 |
+
|
322 |
+
for ($i = 0; $i < $len; $i+= 4) {
|
323 |
+
$this->value = bcmul($this->value, '4294967296', 0); // 4294967296 == 2**32
|
324 |
+
$this->value = bcadd($this->value, 0x1000000 * ord($x[$i]) + ((ord($x[$i + 1]) << 16) | (ord($x[$i + 2]) << 8) | ord($x[$i + 3])), 0);
|
325 |
+
}
|
326 |
+
|
327 |
+
if ($this->is_negative) {
|
328 |
+
$this->value = '-' . $this->value;
|
329 |
+
}
|
330 |
+
|
331 |
+
break;
|
332 |
+
// converts a base-2**8 (big endian / msb) number to base-2**26 (little endian / lsb)
|
333 |
+
default:
|
334 |
+
while (strlen($x)) {
|
335 |
+
$this->value[] = $this->_bytes2int($this->_base256_rshift($x, 26));
|
336 |
+
}
|
337 |
+
}
|
338 |
+
|
339 |
+
if ($this->is_negative) {
|
340 |
+
if (MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL) {
|
341 |
+
$this->is_negative = false;
|
342 |
+
}
|
343 |
+
$temp = $this->add(new Math_BigInteger('-1'));
|
344 |
+
$this->value = $temp->value;
|
345 |
+
}
|
346 |
+
break;
|
347 |
+
case 16:
|
348 |
+
case -16:
|
349 |
+
if ($base > 0 && $x[0] == '-') {
|
350 |
+
$this->is_negative = true;
|
351 |
+
$x = substr($x, 1);
|
352 |
+
}
|
353 |
+
|
354 |
+
$x = preg_replace('#^(?:0x)?([A-Fa-f0-9]*).*#', '$1', $x);
|
355 |
+
|
356 |
+
$is_negative = false;
|
357 |
+
if ($base < 0 && hexdec($x[0]) >= 8) {
|
358 |
+
$this->is_negative = $is_negative = true;
|
359 |
+
$x = bin2hex(~pack('H*', $x));
|
360 |
+
}
|
361 |
+
|
362 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
363 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
364 |
+
$temp = $this->is_negative ? '-0x' . $x : '0x' . $x;
|
365 |
+
$this->value = gmp_init($temp);
|
366 |
+
$this->is_negative = false;
|
367 |
+
break;
|
368 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
369 |
+
$x = ( strlen($x) & 1 ) ? '0' . $x : $x;
|
370 |
+
$temp = new Math_BigInteger(pack('H*', $x), 256);
|
371 |
+
$this->value = $this->is_negative ? '-' . $temp->value : $temp->value;
|
372 |
+
$this->is_negative = false;
|
373 |
+
break;
|
374 |
+
default:
|
375 |
+
$x = ( strlen($x) & 1 ) ? '0' . $x : $x;
|
376 |
+
$temp = new Math_BigInteger(pack('H*', $x), 256);
|
377 |
+
$this->value = $temp->value;
|
378 |
+
}
|
379 |
+
|
380 |
+
if ($is_negative) {
|
381 |
+
$temp = $this->add(new Math_BigInteger('-1'));
|
382 |
+
$this->value = $temp->value;
|
383 |
+
}
|
384 |
+
break;
|
385 |
+
case 10:
|
386 |
+
case -10:
|
387 |
+
$x = preg_replace('#^(-?[0-9]*).*#', '$1', $x);
|
388 |
+
|
389 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
390 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
391 |
+
$this->value = gmp_init($x);
|
392 |
+
break;
|
393 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
394 |
+
// explicitly casting $x to a string is necessary, here, since doing $x[0] on -1 yields different
|
395 |
+
// results then doing it on '-1' does (modInverse does $x[0])
|
396 |
+
$this->value = (string) $x;
|
397 |
+
break;
|
398 |
+
default:
|
399 |
+
$temp = new Math_BigInteger();
|
400 |
+
|
401 |
+
// array(10000000) is 10**7 in base-2**26. 10**7 is the closest to 2**26 we can get without passing it.
|
402 |
+
$multiplier = new Math_BigInteger();
|
403 |
+
$multiplier->value = array(10000000);
|
404 |
+
|
405 |
+
if ($x[0] == '-') {
|
406 |
+
$this->is_negative = true;
|
407 |
+
$x = substr($x, 1);
|
408 |
+
}
|
409 |
+
|
410 |
+
$x = str_pad($x, strlen($x) + (6 * strlen($x)) % 7, 0, STR_PAD_LEFT);
|
411 |
+
|
412 |
+
while (strlen($x)) {
|
413 |
+
$temp = $temp->multiply($multiplier);
|
414 |
+
$temp = $temp->add(new Math_BigInteger($this->_int2bytes(substr($x, 0, 7)), 256));
|
415 |
+
$x = substr($x, 7);
|
416 |
+
}
|
417 |
+
|
418 |
+
$this->value = $temp->value;
|
419 |
+
}
|
420 |
+
break;
|
421 |
+
case 2: // base-2 support originally implemented by Lluis Pamies - thanks!
|
422 |
+
case -2:
|
423 |
+
if ($base > 0 && $x[0] == '-') {
|
424 |
+
$this->is_negative = true;
|
425 |
+
$x = substr($x, 1);
|
426 |
+
}
|
427 |
+
|
428 |
+
$x = preg_replace('#^([01]*).*#', '$1', $x);
|
429 |
+
$x = str_pad($x, strlen($x) + (3 * strlen($x)) % 4, 0, STR_PAD_LEFT);
|
430 |
+
|
431 |
+
$str = '0x';
|
432 |
+
while (strlen($x)) {
|
433 |
+
$part = substr($x, 0, 4);
|
434 |
+
$str.= dechex(bindec($part));
|
435 |
+
$x = substr($x, 4);
|
436 |
+
}
|
437 |
+
|
438 |
+
if ($this->is_negative) {
|
439 |
+
$str = '-' . $str;
|
440 |
+
}
|
441 |
+
|
442 |
+
$temp = new Math_BigInteger($str, 8 * $base); // ie. either -16 or +16
|
443 |
+
$this->value = $temp->value;
|
444 |
+
$this->is_negative = $temp->is_negative;
|
445 |
+
|
446 |
+
break;
|
447 |
+
default:
|
448 |
+
// base not supported, so we'll let $this == 0
|
449 |
+
}
|
450 |
+
}
|
451 |
+
|
452 |
+
/**
|
453 |
+
* Converts a BigInteger to a byte string (eg. base-256).
|
454 |
+
*
|
455 |
+
* Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
|
456 |
+
* saved as two's compliment.
|
457 |
+
*
|
458 |
+
* Here's an example:
|
459 |
+
* <code>
|
460 |
+
* <?php
|
461 |
+
* include('Math/BigInteger.php');
|
462 |
+
*
|
463 |
+
* $a = new Math_BigInteger('65');
|
464 |
+
*
|
465 |
+
* echo $a->toBytes(); // outputs chr(65)
|
466 |
+
* ?>
|
467 |
+
* </code>
|
468 |
+
*
|
469 |
+
* @param Boolean $twos_compliment
|
470 |
+
* @return String
|
471 |
+
* @access public
|
472 |
+
* @internal Converts a base-2**26 number to base-2**8
|
473 |
+
*/
|
474 |
+
function toBytes($twos_compliment = false)
|
475 |
+
{
|
476 |
+
if ($twos_compliment) {
|
477 |
+
$comparison = $this->compare(new Math_BigInteger());
|
478 |
+
if ($comparison == 0) {
|
479 |
+
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
|
480 |
+
}
|
481 |
+
|
482 |
+
$temp = $comparison < 0 ? $this->add(new Math_BigInteger(1)) : $this->copy();
|
483 |
+
$bytes = $temp->toBytes();
|
484 |
+
|
485 |
+
if (empty($bytes)) { // eg. if the number we're trying to convert is -1
|
486 |
+
$bytes = chr(0);
|
487 |
+
}
|
488 |
+
|
489 |
+
if (ord($bytes[0]) & 0x80) {
|
490 |
+
$bytes = chr(0) . $bytes;
|
491 |
+
}
|
492 |
+
|
493 |
+
return $comparison < 0 ? ~$bytes : $bytes;
|
494 |
+
}
|
495 |
+
|
496 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
497 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
498 |
+
if (gmp_cmp($this->value, gmp_init(0)) == 0) {
|
499 |
+
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
|
500 |
+
}
|
501 |
+
|
502 |
+
$temp = gmp_strval(gmp_abs($this->value), 16);
|
503 |
+
$temp = ( strlen($temp) & 1 ) ? '0' . $temp : $temp;
|
504 |
+
$temp = pack('H*', $temp);
|
505 |
+
|
506 |
+
return $this->precision > 0 ?
|
507 |
+
substr(str_pad($temp, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
|
508 |
+
ltrim($temp, chr(0));
|
509 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
510 |
+
if ($this->value === '0') {
|
511 |
+
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
|
512 |
+
}
|
513 |
+
|
514 |
+
$value = '';
|
515 |
+
$current = $this->value;
|
516 |
+
|
517 |
+
if ($current[0] == '-') {
|
518 |
+
$current = substr($current, 1);
|
519 |
+
}
|
520 |
+
|
521 |
+
while (bccomp($current, '0', 0) > 0) {
|
522 |
+
$temp = bcmod($current, '16777216');
|
523 |
+
$value = chr($temp >> 16) . chr($temp >> 8) . chr($temp) . $value;
|
524 |
+
$current = bcdiv($current, '16777216', 0);
|
525 |
+
}
|
526 |
+
|
527 |
+
return $this->precision > 0 ?
|
528 |
+
substr(str_pad($value, $this->precision >> 3, chr(0), STR_PAD_LEFT), -($this->precision >> 3)) :
|
529 |
+
ltrim($value, chr(0));
|
530 |
+
}
|
531 |
+
|
532 |
+
if (!count($this->value)) {
|
533 |
+
return $this->precision > 0 ? str_repeat(chr(0), ($this->precision + 1) >> 3) : '';
|
534 |
+
}
|
535 |
+
$result = $this->_int2bytes($this->value[count($this->value) - 1]);
|
536 |
+
|
537 |
+
$temp = $this->copy();
|
538 |
+
|
539 |
+
for ($i = count($temp->value) - 2; $i >= 0; --$i) {
|
540 |
+
$temp->_base256_lshift($result, 26);
|
541 |
+
$result = $result | str_pad($temp->_int2bytes($temp->value[$i]), strlen($result), chr(0), STR_PAD_LEFT);
|
542 |
+
}
|
543 |
+
|
544 |
+
return $this->precision > 0 ?
|
545 |
+
str_pad(substr($result, -(($this->precision + 7) >> 3)), ($this->precision + 7) >> 3, chr(0), STR_PAD_LEFT) :
|
546 |
+
$result;
|
547 |
+
}
|
548 |
+
|
549 |
+
/**
|
550 |
+
* Converts a BigInteger to a hex string (eg. base-16)).
|
551 |
+
*
|
552 |
+
* Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
|
553 |
+
* saved as two's compliment.
|
554 |
+
*
|
555 |
+
* Here's an example:
|
556 |
+
* <code>
|
557 |
+
* <?php
|
558 |
+
* include('Math/BigInteger.php');
|
559 |
+
*
|
560 |
+
* $a = new Math_BigInteger('65');
|
561 |
+
*
|
562 |
+
* echo $a->toHex(); // outputs '41'
|
563 |
+
* ?>
|
564 |
+
* </code>
|
565 |
+
*
|
566 |
+
* @param Boolean $twos_compliment
|
567 |
+
* @return String
|
568 |
+
* @access public
|
569 |
+
* @internal Converts a base-2**26 number to base-2**8
|
570 |
+
*/
|
571 |
+
function toHex($twos_compliment = false)
|
572 |
+
{
|
573 |
+
return bin2hex($this->toBytes($twos_compliment));
|
574 |
+
}
|
575 |
+
|
576 |
+
/**
|
577 |
+
* Converts a BigInteger to a bit string (eg. base-2).
|
578 |
+
*
|
579 |
+
* Negative numbers are saved as positive numbers, unless $twos_compliment is set to true, at which point, they're
|
580 |
+
* saved as two's compliment.
|
581 |
+
*
|
582 |
+
* Here's an example:
|
583 |
+
* <code>
|
584 |
+
* <?php
|
585 |
+
* include('Math/BigInteger.php');
|
586 |
+
*
|
587 |
+
* $a = new Math_BigInteger('65');
|
588 |
+
*
|
589 |
+
* echo $a->toBits(); // outputs '1000001'
|
590 |
+
* ?>
|
591 |
+
* </code>
|
592 |
+
*
|
593 |
+
* @param Boolean $twos_compliment
|
594 |
+
* @return String
|
595 |
+
* @access public
|
596 |
+
* @internal Converts a base-2**26 number to base-2**2
|
597 |
+
*/
|
598 |
+
function toBits($twos_compliment = false)
|
599 |
+
{
|
600 |
+
$hex = $this->toHex($twos_compliment);
|
601 |
+
$bits = '';
|
602 |
+
for ($i = 0, $end = strlen($hex) & 0xFFFFFFF8; $i < $end; $i+=8) {
|
603 |
+
$bits.= str_pad(decbin(hexdec(substr($hex, $i, 8))), 32, '0', STR_PAD_LEFT);
|
604 |
+
}
|
605 |
+
if ($end != strlen($hex)) { // hexdec('') == 0
|
606 |
+
$bits.= str_pad(decbin(hexdec(substr($hex, $end))), strlen($hex) & 7, '0', STR_PAD_LEFT);
|
607 |
+
}
|
608 |
+
return $this->precision > 0 ? substr($bits, -$this->precision) : ltrim($bits, '0');
|
609 |
+
}
|
610 |
+
|
611 |
+
/**
|
612 |
+
* Converts a BigInteger to a base-10 number.
|
613 |
+
*
|
614 |
+
* Here's an example:
|
615 |
+
* <code>
|
616 |
+
* <?php
|
617 |
+
* include('Math/BigInteger.php');
|
618 |
+
*
|
619 |
+
* $a = new Math_BigInteger('50');
|
620 |
+
*
|
621 |
+
* echo $a->toString(); // outputs 50
|
622 |
+
* ?>
|
623 |
+
* </code>
|
624 |
+
*
|
625 |
+
* @return String
|
626 |
+
* @access public
|
627 |
+
* @internal Converts a base-2**26 number to base-10**7 (which is pretty much base-10)
|
628 |
+
*/
|
629 |
+
function toString()
|
630 |
+
{
|
631 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
632 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
633 |
+
return gmp_strval($this->value);
|
634 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
635 |
+
if ($this->value === '0') {
|
636 |
+
return '0';
|
637 |
+
}
|
638 |
+
|
639 |
+
return ltrim($this->value, '0');
|
640 |
+
}
|
641 |
+
|
642 |
+
if (!count($this->value)) {
|
643 |
+
return '0';
|
644 |
+
}
|
645 |
+
|
646 |
+
$temp = $this->copy();
|
647 |
+
$temp->is_negative = false;
|
648 |
+
|
649 |
+
$divisor = new Math_BigInteger();
|
650 |
+
$divisor->value = array(10000000); // eg. 10**7
|
651 |
+
$result = '';
|
652 |
+
while (count($temp->value)) {
|
653 |
+
list($temp, $mod) = $temp->divide($divisor);
|
654 |
+
$result = str_pad(isset($mod->value[0]) ? $mod->value[0] : '', 7, '0', STR_PAD_LEFT) . $result;
|
655 |
+
}
|
656 |
+
$result = ltrim($result, '0');
|
657 |
+
if (empty($result)) {
|
658 |
+
$result = '0';
|
659 |
+
}
|
660 |
+
|
661 |
+
if ($this->is_negative) {
|
662 |
+
$result = '-' . $result;
|
663 |
+
}
|
664 |
+
|
665 |
+
return $result;
|
666 |
+
}
|
667 |
+
|
668 |
+
/**
|
669 |
+
* Copy an object
|
670 |
+
*
|
671 |
+
* PHP5 passes objects by reference while PHP4 passes by value. As such, we need a function to guarantee
|
672 |
+
* that all objects are passed by value, when appropriate. More information can be found here:
|
673 |
+
*
|
674 |
+
* {@link http://php.net/language.oop5.basic#51624}
|
675 |
+
*
|
676 |
+
* @access public
|
677 |
+
* @see __clone()
|
678 |
+
* @return Math_BigInteger
|
679 |
+
*/
|
680 |
+
function copy()
|
681 |
+
{
|
682 |
+
$temp = new Math_BigInteger();
|
683 |
+
$temp->value = $this->value;
|
684 |
+
$temp->is_negative = $this->is_negative;
|
685 |
+
$temp->generator = $this->generator;
|
686 |
+
$temp->precision = $this->precision;
|
687 |
+
$temp->bitmask = $this->bitmask;
|
688 |
+
return $temp;
|
689 |
+
}
|
690 |
+
|
691 |
+
/**
|
692 |
+
* __toString() magic method
|
693 |
+
*
|
694 |
+
* Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
|
695 |
+
* toString().
|
696 |
+
*
|
697 |
+
* @access public
|
698 |
+
* @internal Implemented per a suggestion by Techie-Michael - thanks!
|
699 |
+
*/
|
700 |
+
function __toString()
|
701 |
+
{
|
702 |
+
return $this->toString();
|
703 |
+
}
|
704 |
+
|
705 |
+
/**
|
706 |
+
* __clone() magic method
|
707 |
+
*
|
708 |
+
* Although you can call Math_BigInteger::__toString() directly in PHP5, you cannot call Math_BigInteger::__clone()
|
709 |
+
* directly in PHP5. You can in PHP4 since it's not a magic method, but in PHP5, you have to call it by using the PHP5
|
710 |
+
* only syntax of $y = clone $x. As such, if you're trying to write an application that works on both PHP4 and PHP5,
|
711 |
+
* call Math_BigInteger::copy(), instead.
|
712 |
+
*
|
713 |
+
* @access public
|
714 |
+
* @see copy()
|
715 |
+
* @return Math_BigInteger
|
716 |
+
*/
|
717 |
+
function __clone()
|
718 |
+
{
|
719 |
+
return $this->copy();
|
720 |
+
}
|
721 |
+
|
722 |
+
/**
|
723 |
+
* __sleep() magic method
|
724 |
+
*
|
725 |
+
* Will be called, automatically, when serialize() is called on a Math_BigInteger object.
|
726 |
+
*
|
727 |
+
* @see __wakeup()
|
728 |
+
* @access public
|
729 |
+
*/
|
730 |
+
function __sleep()
|
731 |
+
{
|
732 |
+
$this->hex = $this->toHex(true);
|
733 |
+
$vars = array('hex');
|
734 |
+
if ($this->generator != 'mt_rand') {
|
735 |
+
$vars[] = 'generator';
|
736 |
+
}
|
737 |
+
if ($this->precision > 0) {
|
738 |
+
$vars[] = 'precision';
|
739 |
+
}
|
740 |
+
return $vars;
|
741 |
+
|
742 |
+
}
|
743 |
+
|
744 |
+
/**
|
745 |
+
* __wakeup() magic method
|
746 |
+
*
|
747 |
+
* Will be called, automatically, when unserialize() is called on a Math_BigInteger object.
|
748 |
+
*
|
749 |
+
* @see __sleep()
|
750 |
+
* @access public
|
751 |
+
*/
|
752 |
+
function __wakeup()
|
753 |
+
{
|
754 |
+
$temp = new Math_BigInteger($this->hex, -16);
|
755 |
+
$this->value = $temp->value;
|
756 |
+
$this->is_negative = $temp->is_negative;
|
757 |
+
$this->setRandomGenerator($this->generator);
|
758 |
+
if ($this->precision > 0) {
|
759 |
+
// recalculate $this->bitmask
|
760 |
+
$this->setPrecision($this->precision);
|
761 |
+
}
|
762 |
+
}
|
763 |
+
|
764 |
+
/**
|
765 |
+
* Adds two BigIntegers.
|
766 |
+
*
|
767 |
+
* Here's an example:
|
768 |
+
* <code>
|
769 |
+
* <?php
|
770 |
+
* include('Math/BigInteger.php');
|
771 |
+
*
|
772 |
+
* $a = new Math_BigInteger('10');
|
773 |
+
* $b = new Math_BigInteger('20');
|
774 |
+
*
|
775 |
+
* $c = $a->add($b);
|
776 |
+
*
|
777 |
+
* echo $c->toString(); // outputs 30
|
778 |
+
* ?>
|
779 |
+
* </code>
|
780 |
+
*
|
781 |
+
* @param Math_BigInteger $y
|
782 |
+
* @return Math_BigInteger
|
783 |
+
* @access public
|
784 |
+
* @internal Performs base-2**52 addition
|
785 |
+
*/
|
786 |
+
function add($y)
|
787 |
+
{
|
788 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
789 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
790 |
+
$temp = new Math_BigInteger();
|
791 |
+
$temp->value = gmp_add($this->value, $y->value);
|
792 |
+
|
793 |
+
return $this->_normalize($temp);
|
794 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
795 |
+
$temp = new Math_BigInteger();
|
796 |
+
$temp->value = bcadd($this->value, $y->value, 0);
|
797 |
+
|
798 |
+
return $this->_normalize($temp);
|
799 |
+
}
|
800 |
+
|
801 |
+
$temp = $this->_add($this->value, $this->is_negative, $y->value, $y->is_negative);
|
802 |
+
|
803 |
+
$result = new Math_BigInteger();
|
804 |
+
$result->value = $temp[MATH_BIGINTEGER_VALUE];
|
805 |
+
$result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
|
806 |
+
|
807 |
+
return $this->_normalize($result);
|
808 |
+
}
|
809 |
+
|
810 |
+
/**
|
811 |
+
* Performs addition.
|
812 |
+
*
|
813 |
+
* @param Array $x_value
|
814 |
+
* @param Boolean $x_negative
|
815 |
+
* @param Array $y_value
|
816 |
+
* @param Boolean $y_negative
|
817 |
+
* @return Array
|
818 |
+
* @access private
|
819 |
+
*/
|
820 |
+
function _add($x_value, $x_negative, $y_value, $y_negative)
|
821 |
+
{
|
822 |
+
$x_size = count($x_value);
|
823 |
+
$y_size = count($y_value);
|
824 |
+
|
825 |
+
if ($x_size == 0) {
|
826 |
+
return array(
|
827 |
+
MATH_BIGINTEGER_VALUE => $y_value,
|
828 |
+
MATH_BIGINTEGER_SIGN => $y_negative
|
829 |
+
);
|
830 |
+
} else if ($y_size == 0) {
|
831 |
+
return array(
|
832 |
+
MATH_BIGINTEGER_VALUE => $x_value,
|
833 |
+
MATH_BIGINTEGER_SIGN => $x_negative
|
834 |
+
);
|
835 |
+
}
|
836 |
+
|
837 |
+
// subtract, if appropriate
|
838 |
+
if ( $x_negative != $y_negative ) {
|
839 |
+
if ( $x_value == $y_value ) {
|
840 |
+
return array(
|
841 |
+
MATH_BIGINTEGER_VALUE => array(),
|
842 |
+
MATH_BIGINTEGER_SIGN => false
|
843 |
+
);
|
844 |
+
}
|
845 |
+
|
846 |
+
$temp = $this->_subtract($x_value, false, $y_value, false);
|
847 |
+
$temp[MATH_BIGINTEGER_SIGN] = $this->_compare($x_value, false, $y_value, false) > 0 ?
|
848 |
+
$x_negative : $y_negative;
|
849 |
+
|
850 |
+
return $temp;
|
851 |
+
}
|
852 |
+
|
853 |
+
if ($x_size < $y_size) {
|
854 |
+
$size = $x_size;
|
855 |
+
$value = $y_value;
|
856 |
+
} else {
|
857 |
+
$size = $y_size;
|
858 |
+
$value = $x_value;
|
859 |
+
}
|
860 |
+
|
861 |
+
$value[] = 0; // just in case the carry adds an extra digit
|
862 |
+
|
863 |
+
$carry = 0;
|
864 |
+
for ($i = 0, $j = 1; $j < $size; $i+=2, $j+=2) {
|
865 |
+
$sum = $x_value[$j] * 0x4000000 + $x_value[$i] + $y_value[$j] * 0x4000000 + $y_value[$i] + $carry;
|
866 |
+
$carry = $sum >= MATH_BIGINTEGER_MAX_DIGIT52; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
|
867 |
+
$sum = $carry ? $sum - MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
|
868 |
+
|
869 |
+
$temp = (int) ($sum / 0x4000000);
|
870 |
+
|
871 |
+
$value[$i] = (int) ($sum - 0x4000000 * $temp); // eg. a faster alternative to fmod($sum, 0x4000000)
|
872 |
+
$value[$j] = $temp;
|
873 |
+
}
|
874 |
+
|
875 |
+
if ($j == $size) { // ie. if $y_size is odd
|
876 |
+
$sum = $x_value[$i] + $y_value[$i] + $carry;
|
877 |
+
$carry = $sum >= 0x4000000;
|
878 |
+
$value[$i] = $carry ? $sum - 0x4000000 : $sum;
|
879 |
+
++$i; // ie. let $i = $j since we've just done $value[$i]
|
880 |
+
}
|
881 |
+
|
882 |
+
if ($carry) {
|
883 |
+
for (; $value[$i] == 0x3FFFFFF; ++$i) {
|
884 |
+
$value[$i] = 0;
|
885 |
+
}
|
886 |
+
++$value[$i];
|
887 |
+
}
|
888 |
+
|
889 |
+
return array(
|
890 |
+
MATH_BIGINTEGER_VALUE => $this->_trim($value),
|
891 |
+
MATH_BIGINTEGER_SIGN => $x_negative
|
892 |
+
);
|
893 |
+
}
|
894 |
+
|
895 |
+
/**
|
896 |
+
* Subtracts two BigIntegers.
|
897 |
+
*
|
898 |
+
* Here's an example:
|
899 |
+
* <code>
|
900 |
+
* <?php
|
901 |
+
* include('Math/BigInteger.php');
|
902 |
+
*
|
903 |
+
* $a = new Math_BigInteger('10');
|
904 |
+
* $b = new Math_BigInteger('20');
|
905 |
+
*
|
906 |
+
* $c = $a->subtract($b);
|
907 |
+
*
|
908 |
+
* echo $c->toString(); // outputs -10
|
909 |
+
* ?>
|
910 |
+
* </code>
|
911 |
+
*
|
912 |
+
* @param Math_BigInteger $y
|
913 |
+
* @return Math_BigInteger
|
914 |
+
* @access public
|
915 |
+
* @internal Performs base-2**52 subtraction
|
916 |
+
*/
|
917 |
+
function subtract($y)
|
918 |
+
{
|
919 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
920 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
921 |
+
$temp = new Math_BigInteger();
|
922 |
+
$temp->value = gmp_sub($this->value, $y->value);
|
923 |
+
|
924 |
+
return $this->_normalize($temp);
|
925 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
926 |
+
$temp = new Math_BigInteger();
|
927 |
+
$temp->value = bcsub($this->value, $y->value, 0);
|
928 |
+
|
929 |
+
return $this->_normalize($temp);
|
930 |
+
}
|
931 |
+
|
932 |
+
$temp = $this->_subtract($this->value, $this->is_negative, $y->value, $y->is_negative);
|
933 |
+
|
934 |
+
$result = new Math_BigInteger();
|
935 |
+
$result->value = $temp[MATH_BIGINTEGER_VALUE];
|
936 |
+
$result->is_negative = $temp[MATH_BIGINTEGER_SIGN];
|
937 |
+
|
938 |
+
return $this->_normalize($result);
|
939 |
+
}
|
940 |
+
|
941 |
+
/**
|
942 |
+
* Performs subtraction.
|
943 |
+
*
|
944 |
+
* @param Array $x_value
|
945 |
+
* @param Boolean $x_negative
|
946 |
+
* @param Array $y_value
|
947 |
+
* @param Boolean $y_negative
|
948 |
+
* @return Array
|
949 |
+
* @access private
|
950 |
+
*/
|
951 |
+
function _subtract($x_value, $x_negative, $y_value, $y_negative)
|
952 |
+
{
|
953 |
+
$x_size = count($x_value);
|
954 |
+
$y_size = count($y_value);
|
955 |
+
|
956 |
+
if ($x_size == 0) {
|
957 |
+
return array(
|
958 |
+
MATH_BIGINTEGER_VALUE => $y_value,
|
959 |
+
MATH_BIGINTEGER_SIGN => !$y_negative
|
960 |
+
);
|
961 |
+
} else if ($y_size == 0) {
|
962 |
+
return array(
|
963 |
+
MATH_BIGINTEGER_VALUE => $x_value,
|
964 |
+
MATH_BIGINTEGER_SIGN => $x_negative
|
965 |
+
);
|
966 |
+
}
|
967 |
+
|
968 |
+
// add, if appropriate (ie. -$x - +$y or +$x - -$y)
|
969 |
+
if ( $x_negative != $y_negative ) {
|
970 |
+
$temp = $this->_add($x_value, false, $y_value, false);
|
971 |
+
$temp[MATH_BIGINTEGER_SIGN] = $x_negative;
|
972 |
+
|
973 |
+
return $temp;
|
974 |
+
}
|
975 |
+
|
976 |
+
$diff = $this->_compare($x_value, $x_negative, $y_value, $y_negative);
|
977 |
+
|
978 |
+
if ( !$diff ) {
|
979 |
+
return array(
|
980 |
+
MATH_BIGINTEGER_VALUE => array(),
|
981 |
+
MATH_BIGINTEGER_SIGN => false
|
982 |
+
);
|
983 |
+
}
|
984 |
+
|
985 |
+
// switch $x and $y around, if appropriate.
|
986 |
+
if ( (!$x_negative && $diff < 0) || ($x_negative && $diff > 0) ) {
|
987 |
+
$temp = $x_value;
|
988 |
+
$x_value = $y_value;
|
989 |
+
$y_value = $temp;
|
990 |
+
|
991 |
+
$x_negative = !$x_negative;
|
992 |
+
|
993 |
+
$x_size = count($x_value);
|
994 |
+
$y_size = count($y_value);
|
995 |
+
}
|
996 |
+
|
997 |
+
// at this point, $x_value should be at least as big as - if not bigger than - $y_value
|
998 |
+
|
999 |
+
$carry = 0;
|
1000 |
+
for ($i = 0, $j = 1; $j < $y_size; $i+=2, $j+=2) {
|
1001 |
+
$sum = $x_value[$j] * 0x4000000 + $x_value[$i] - $y_value[$j] * 0x4000000 - $y_value[$i] - $carry;
|
1002 |
+
$carry = $sum < 0; // eg. floor($sum / 2**52); only possible values (in any base) are 0 and 1
|
1003 |
+
$sum = $carry ? $sum + MATH_BIGINTEGER_MAX_DIGIT52 : $sum;
|
1004 |
+
|
1005 |
+
$temp = (int) ($sum / 0x4000000);
|
1006 |
+
|
1007 |
+
$x_value[$i] = (int) ($sum - 0x4000000 * $temp);
|
1008 |
+
$x_value[$j] = $temp;
|
1009 |
+
}
|
1010 |
+
|
1011 |
+
if ($j == $y_size) { // ie. if $y_size is odd
|
1012 |
+
$sum = $x_value[$i] - $y_value[$i] - $carry;
|
1013 |
+
$carry = $sum < 0;
|
1014 |
+
$x_value[$i] = $carry ? $sum + 0x4000000 : $sum;
|
1015 |
+
++$i;
|
1016 |
+
}
|
1017 |
+
|
1018 |
+
if ($carry) {
|
1019 |
+
for (; !$x_value[$i]; ++$i) {
|
1020 |
+
$x_value[$i] = 0x3FFFFFF;
|
1021 |
+
}
|
1022 |
+
--$x_value[$i];
|
1023 |
+
}
|
1024 |
+
|
1025 |
+
return array(
|
1026 |
+
MATH_BIGINTEGER_VALUE => $this->_trim($x_value),
|
1027 |
+
MATH_BIGINTEGER_SIGN => $x_negative
|
1028 |
+
);
|
1029 |
+
}
|
1030 |
+
|
1031 |
+
/**
|
1032 |
+
* Multiplies two BigIntegers
|
1033 |
+
*
|
1034 |
+
* Here's an example:
|
1035 |
+
* <code>
|
1036 |
+
* <?php
|
1037 |
+
* include('Math/BigInteger.php');
|
1038 |
+
*
|
1039 |
+
* $a = new Math_BigInteger('10');
|
1040 |
+
* $b = new Math_BigInteger('20');
|
1041 |
+
*
|
1042 |
+
* $c = $a->multiply($b);
|
1043 |
+
*
|
1044 |
+
* echo $c->toString(); // outputs 200
|
1045 |
+
* ?>
|
1046 |
+
* </code>
|
1047 |
+
*
|
1048 |
+
* @param Math_BigInteger $x
|
1049 |
+
* @return Math_BigInteger
|
1050 |
+
* @access public
|
1051 |
+
*/
|
1052 |
+
function multiply($x)
|
1053 |
+
{
|
1054 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
1055 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
1056 |
+
$temp = new Math_BigInteger();
|
1057 |
+
$temp->value = gmp_mul($this->value, $x->value);
|
1058 |
+
|
1059 |
+
return $this->_normalize($temp);
|
1060 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
1061 |
+
$temp = new Math_BigInteger();
|
1062 |
+
$temp->value = bcmul($this->value, $x->value, 0);
|
1063 |
+
|
1064 |
+
return $this->_normalize($temp);
|
1065 |
+
}
|
1066 |
+
|
1067 |
+
$temp = $this->_multiply($this->value, $this->is_negative, $x->value, $x->is_negative);
|
1068 |
+
|
1069 |
+
$product = new Math_BigInteger();
|
1070 |
+
$product->value = $temp[MATH_BIGINTEGER_VALUE];
|
1071 |
+
$product->is_negative = $temp[MATH_BIGINTEGER_SIGN];
|
1072 |
+
|
1073 |
+
return $this->_normalize($product);
|
1074 |
+
}
|
1075 |
+
|
1076 |
+
/**
|
1077 |
+
* Performs multiplication.
|
1078 |
+
*
|
1079 |
+
* @param Array $x_value
|
1080 |
+
* @param Boolean $x_negative
|
1081 |
+
* @param Array $y_value
|
1082 |
+
* @param Boolean $y_negative
|
1083 |
+
* @return Array
|
1084 |
+
* @access private
|
1085 |
+
*/
|
1086 |
+
function _multiply($x_value, $x_negative, $y_value, $y_negative)
|
1087 |
+
{
|
1088 |
+
//if ( $x_value == $y_value ) {
|
1089 |
+
// return array(
|
1090 |
+
// MATH_BIGINTEGER_VALUE => $this->_square($x_value),
|
1091 |
+
// MATH_BIGINTEGER_SIGN => $x_sign != $y_value
|
1092 |
+
// );
|
1093 |
+
//}
|
1094 |
+
|
1095 |
+
$x_length = count($x_value);
|
1096 |
+
$y_length = count($y_value);
|
1097 |
+
|
1098 |
+
if ( !$x_length || !$y_length ) { // a 0 is being multiplied
|
1099 |
+
return array(
|
1100 |
+
MATH_BIGINTEGER_VALUE => array(),
|
1101 |
+
MATH_BIGINTEGER_SIGN => false
|
1102 |
+
);
|
1103 |
+
}
|
1104 |
+
|
1105 |
+
return array(
|
1106 |
+
MATH_BIGINTEGER_VALUE => min($x_length, $y_length) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
|
1107 |
+
$this->_trim($this->_regularMultiply($x_value, $y_value)) :
|
1108 |
+
$this->_trim($this->_karatsuba($x_value, $y_value)),
|
1109 |
+
MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
|
1110 |
+
);
|
1111 |
+
}
|
1112 |
+
|
1113 |
+
/**
|
1114 |
+
* Performs long multiplication on two BigIntegers
|
1115 |
+
*
|
1116 |
+
* Modeled after 'multiply' in MutableBigInteger.java.
|
1117 |
+
*
|
1118 |
+
* @param Array $x_value
|
1119 |
+
* @param Array $y_value
|
1120 |
+
* @return Array
|
1121 |
+
* @access private
|
1122 |
+
*/
|
1123 |
+
function _regularMultiply($x_value, $y_value)
|
1124 |
+
{
|
1125 |
+
$x_length = count($x_value);
|
1126 |
+
$y_length = count($y_value);
|
1127 |
+
|
1128 |
+
if ( !$x_length || !$y_length ) { // a 0 is being multiplied
|
1129 |
+
return array();
|
1130 |
+
}
|
1131 |
+
|
1132 |
+
if ( $x_length < $y_length ) {
|
1133 |
+
$temp = $x_value;
|
1134 |
+
$x_value = $y_value;
|
1135 |
+
$y_value = $temp;
|
1136 |
+
|
1137 |
+
$x_length = count($x_value);
|
1138 |
+
$y_length = count($y_value);
|
1139 |
+
}
|
1140 |
+
|
1141 |
+
$product_value = $this->_array_repeat(0, $x_length + $y_length);
|
1142 |
+
|
1143 |
+
// the following for loop could be removed if the for loop following it
|
1144 |
+
// (the one with nested for loops) initially set $i to 0, but
|
1145 |
+
// doing so would also make the result in one set of unnecessary adds,
|
1146 |
+
// since on the outermost loops first pass, $product->value[$k] is going
|
1147 |
+
// to always be 0
|
1148 |
+
|
1149 |
+
$carry = 0;
|
1150 |
+
|
1151 |
+
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0
|
1152 |
+
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
|
1153 |
+
$carry = (int) ($temp / 0x4000000);
|
1154 |
+
$product_value[$j] = (int) ($temp - 0x4000000 * $carry);
|
1155 |
+
}
|
1156 |
+
|
1157 |
+
$product_value[$j] = $carry;
|
1158 |
+
|
1159 |
+
// the above for loop is what the previous comment was talking about. the
|
1160 |
+
// following for loop is the "one with nested for loops"
|
1161 |
+
for ($i = 1; $i < $y_length; ++$i) {
|
1162 |
+
$carry = 0;
|
1163 |
+
|
1164 |
+
for ($j = 0, $k = $i; $j < $x_length; ++$j, ++$k) {
|
1165 |
+
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
|
1166 |
+
$carry = (int) ($temp / 0x4000000);
|
1167 |
+
$product_value[$k] = (int) ($temp - 0x4000000 * $carry);
|
1168 |
+
}
|
1169 |
+
|
1170 |
+
$product_value[$k] = $carry;
|
1171 |
+
}
|
1172 |
+
|
1173 |
+
return $product_value;
|
1174 |
+
}
|
1175 |
+
|
1176 |
+
/**
|
1177 |
+
* Performs Karatsuba multiplication on two BigIntegers
|
1178 |
+
*
|
1179 |
+
* See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
|
1180 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=120 MPM 5.2.3}.
|
1181 |
+
*
|
1182 |
+
* @param Array $x_value
|
1183 |
+
* @param Array $y_value
|
1184 |
+
* @return Array
|
1185 |
+
* @access private
|
1186 |
+
*/
|
1187 |
+
function _karatsuba($x_value, $y_value)
|
1188 |
+
{
|
1189 |
+
$m = min(count($x_value) >> 1, count($y_value) >> 1);
|
1190 |
+
|
1191 |
+
if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
|
1192 |
+
return $this->_regularMultiply($x_value, $y_value);
|
1193 |
+
}
|
1194 |
+
|
1195 |
+
$x1 = array_slice($x_value, $m);
|
1196 |
+
$x0 = array_slice($x_value, 0, $m);
|
1197 |
+
$y1 = array_slice($y_value, $m);
|
1198 |
+
$y0 = array_slice($y_value, 0, $m);
|
1199 |
+
|
1200 |
+
$z2 = $this->_karatsuba($x1, $y1);
|
1201 |
+
$z0 = $this->_karatsuba($x0, $y0);
|
1202 |
+
|
1203 |
+
$z1 = $this->_add($x1, false, $x0, false);
|
1204 |
+
$temp = $this->_add($y1, false, $y0, false);
|
1205 |
+
$z1 = $this->_karatsuba($z1[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_VALUE]);
|
1206 |
+
$temp = $this->_add($z2, false, $z0, false);
|
1207 |
+
$z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
|
1208 |
+
|
1209 |
+
$z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
|
1210 |
+
$z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
|
1211 |
+
|
1212 |
+
$xy = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
|
1213 |
+
$xy = $this->_add($xy[MATH_BIGINTEGER_VALUE], $xy[MATH_BIGINTEGER_SIGN], $z0, false);
|
1214 |
+
|
1215 |
+
return $xy[MATH_BIGINTEGER_VALUE];
|
1216 |
+
}
|
1217 |
+
|
1218 |
+
/**
|
1219 |
+
* Performs squaring
|
1220 |
+
*
|
1221 |
+
* @param Array $x
|
1222 |
+
* @return Array
|
1223 |
+
* @access private
|
1224 |
+
*/
|
1225 |
+
function _square($x = false)
|
1226 |
+
{
|
1227 |
+
return count($x) < 2 * MATH_BIGINTEGER_KARATSUBA_CUTOFF ?
|
1228 |
+
$this->_trim($this->_baseSquare($x)) :
|
1229 |
+
$this->_trim($this->_karatsubaSquare($x));
|
1230 |
+
}
|
1231 |
+
|
1232 |
+
/**
|
1233 |
+
* Performs traditional squaring on two BigIntegers
|
1234 |
+
*
|
1235 |
+
* Squaring can be done faster than multiplying a number by itself can be. See
|
1236 |
+
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=7 HAC 14.2.4} /
|
1237 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=141 MPM 5.3} for more information.
|
1238 |
+
*
|
1239 |
+
* @param Array $value
|
1240 |
+
* @return Array
|
1241 |
+
* @access private
|
1242 |
+
*/
|
1243 |
+
function _baseSquare($value)
|
1244 |
+
{
|
1245 |
+
if ( empty($value) ) {
|
1246 |
+
return array();
|
1247 |
+
}
|
1248 |
+
$square_value = $this->_array_repeat(0, 2 * count($value));
|
1249 |
+
|
1250 |
+
for ($i = 0, $max_index = count($value) - 1; $i <= $max_index; ++$i) {
|
1251 |
+
$i2 = $i << 1;
|
1252 |
+
|
1253 |
+
$temp = $square_value[$i2] + $value[$i] * $value[$i];
|
1254 |
+
$carry = (int) ($temp / 0x4000000);
|
1255 |
+
$square_value[$i2] = (int) ($temp - 0x4000000 * $carry);
|
1256 |
+
|
1257 |
+
// note how we start from $i+1 instead of 0 as we do in multiplication.
|
1258 |
+
for ($j = $i + 1, $k = $i2 + 1; $j <= $max_index; ++$j, ++$k) {
|
1259 |
+
$temp = $square_value[$k] + 2 * $value[$j] * $value[$i] + $carry;
|
1260 |
+
$carry = (int) ($temp / 0x4000000);
|
1261 |
+
$square_value[$k] = (int) ($temp - 0x4000000 * $carry);
|
1262 |
+
}
|
1263 |
+
|
1264 |
+
// the following line can yield values larger 2**15. at this point, PHP should switch
|
1265 |
+
// over to floats.
|
1266 |
+
$square_value[$i + $max_index + 1] = $carry;
|
1267 |
+
}
|
1268 |
+
|
1269 |
+
return $square_value;
|
1270 |
+
}
|
1271 |
+
|
1272 |
+
/**
|
1273 |
+
* Performs Karatsuba "squaring" on two BigIntegers
|
1274 |
+
*
|
1275 |
+
* See {@link http://en.wikipedia.org/wiki/Karatsuba_algorithm Karatsuba algorithm} and
|
1276 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=151 MPM 5.3.4}.
|
1277 |
+
*
|
1278 |
+
* @param Array $value
|
1279 |
+
* @return Array
|
1280 |
+
* @access private
|
1281 |
+
*/
|
1282 |
+
function _karatsubaSquare($value)
|
1283 |
+
{
|
1284 |
+
$m = count($value) >> 1;
|
1285 |
+
|
1286 |
+
if ($m < MATH_BIGINTEGER_KARATSUBA_CUTOFF) {
|
1287 |
+
return $this->_baseSquare($value);
|
1288 |
+
}
|
1289 |
+
|
1290 |
+
$x1 = array_slice($value, $m);
|
1291 |
+
$x0 = array_slice($value, 0, $m);
|
1292 |
+
|
1293 |
+
$z2 = $this->_karatsubaSquare($x1);
|
1294 |
+
$z0 = $this->_karatsubaSquare($x0);
|
1295 |
+
|
1296 |
+
$z1 = $this->_add($x1, false, $x0, false);
|
1297 |
+
$z1 = $this->_karatsubaSquare($z1[MATH_BIGINTEGER_VALUE]);
|
1298 |
+
$temp = $this->_add($z2, false, $z0, false);
|
1299 |
+
$z1 = $this->_subtract($z1, false, $temp[MATH_BIGINTEGER_VALUE], false);
|
1300 |
+
|
1301 |
+
$z2 = array_merge(array_fill(0, 2 * $m, 0), $z2);
|
1302 |
+
$z1[MATH_BIGINTEGER_VALUE] = array_merge(array_fill(0, $m, 0), $z1[MATH_BIGINTEGER_VALUE]);
|
1303 |
+
|
1304 |
+
$xx = $this->_add($z2, false, $z1[MATH_BIGINTEGER_VALUE], $z1[MATH_BIGINTEGER_SIGN]);
|
1305 |
+
$xx = $this->_add($xx[MATH_BIGINTEGER_VALUE], $xx[MATH_BIGINTEGER_SIGN], $z0, false);
|
1306 |
+
|
1307 |
+
return $xx[MATH_BIGINTEGER_VALUE];
|
1308 |
+
}
|
1309 |
+
|
1310 |
+
/**
|
1311 |
+
* Divides two BigIntegers.
|
1312 |
+
*
|
1313 |
+
* Returns an array whose first element contains the quotient and whose second element contains the
|
1314 |
+
* "common residue". If the remainder would be positive, the "common residue" and the remainder are the
|
1315 |
+
* same. If the remainder would be negative, the "common residue" is equal to the sum of the remainder
|
1316 |
+
* and the divisor (basically, the "common residue" is the first positive modulo).
|
1317 |
+
*
|
1318 |
+
* Here's an example:
|
1319 |
+
* <code>
|
1320 |
+
* <?php
|
1321 |
+
* include('Math/BigInteger.php');
|
1322 |
+
*
|
1323 |
+
* $a = new Math_BigInteger('10');
|
1324 |
+
* $b = new Math_BigInteger('20');
|
1325 |
+
*
|
1326 |
+
* list($quotient, $remainder) = $a->divide($b);
|
1327 |
+
*
|
1328 |
+
* echo $quotient->toString(); // outputs 0
|
1329 |
+
* echo "\r\n";
|
1330 |
+
* echo $remainder->toString(); // outputs 10
|
1331 |
+
* ?>
|
1332 |
+
* </code>
|
1333 |
+
*
|
1334 |
+
* @param Math_BigInteger $y
|
1335 |
+
* @return Array
|
1336 |
+
* @access public
|
1337 |
+
* @internal This function is based off of {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=9 HAC 14.20}.
|
1338 |
+
*/
|
1339 |
+
function divide($y)
|
1340 |
+
{
|
1341 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
1342 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
1343 |
+
$quotient = new Math_BigInteger();
|
1344 |
+
$remainder = new Math_BigInteger();
|
1345 |
+
|
1346 |
+
list($quotient->value, $remainder->value) = gmp_div_qr($this->value, $y->value);
|
1347 |
+
|
1348 |
+
if (gmp_sign($remainder->value) < 0) {
|
1349 |
+
$remainder->value = gmp_add($remainder->value, gmp_abs($y->value));
|
1350 |
+
}
|
1351 |
+
|
1352 |
+
return array($this->_normalize($quotient), $this->_normalize($remainder));
|
1353 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
1354 |
+
$quotient = new Math_BigInteger();
|
1355 |
+
$remainder = new Math_BigInteger();
|
1356 |
+
|
1357 |
+
$quotient->value = bcdiv($this->value, $y->value, 0);
|
1358 |
+
$remainder->value = bcmod($this->value, $y->value);
|
1359 |
+
|
1360 |
+
if ($remainder->value[0] == '-') {
|
1361 |
+
$remainder->value = bcadd($remainder->value, $y->value[0] == '-' ? substr($y->value, 1) : $y->value, 0);
|
1362 |
+
}
|
1363 |
+
|
1364 |
+
return array($this->_normalize($quotient), $this->_normalize($remainder));
|
1365 |
+
}
|
1366 |
+
|
1367 |
+
if (count($y->value) == 1) {
|
1368 |
+
list($q, $r) = $this->_divide_digit($this->value, $y->value[0]);
|
1369 |
+
$quotient = new Math_BigInteger();
|
1370 |
+
$remainder = new Math_BigInteger();
|
1371 |
+
$quotient->value = $q;
|
1372 |
+
$remainder->value = array($r);
|
1373 |
+
$quotient->is_negative = $this->is_negative != $y->is_negative;
|
1374 |
+
return array($this->_normalize($quotient), $this->_normalize($remainder));
|
1375 |
+
}
|
1376 |
+
|
1377 |
+
static $zero;
|
1378 |
+
if ( !isset($zero) ) {
|
1379 |
+
$zero = new Math_BigInteger();
|
1380 |
+
}
|
1381 |
+
|
1382 |
+
$x = $this->copy();
|
1383 |
+
$y = $y->copy();
|
1384 |
+
|
1385 |
+
$x_sign = $x->is_negative;
|
1386 |
+
$y_sign = $y->is_negative;
|
1387 |
+
|
1388 |
+
$x->is_negative = $y->is_negative = false;
|
1389 |
+
|
1390 |
+
$diff = $x->compare($y);
|
1391 |
+
|
1392 |
+
if ( !$diff ) {
|
1393 |
+
$temp = new Math_BigInteger();
|
1394 |
+
$temp->value = array(1);
|
1395 |
+
$temp->is_negative = $x_sign != $y_sign;
|
1396 |
+
return array($this->_normalize($temp), $this->_normalize(new Math_BigInteger()));
|
1397 |
+
}
|
1398 |
+
|
1399 |
+
if ( $diff < 0 ) {
|
1400 |
+
// if $x is negative, "add" $y.
|
1401 |
+
if ( $x_sign ) {
|
1402 |
+
$x = $y->subtract($x);
|
1403 |
+
}
|
1404 |
+
return array($this->_normalize(new Math_BigInteger()), $this->_normalize($x));
|
1405 |
+
}
|
1406 |
+
|
1407 |
+
// normalize $x and $y as described in HAC 14.23 / 14.24
|
1408 |
+
$msb = $y->value[count($y->value) - 1];
|
1409 |
+
for ($shift = 0; !($msb & 0x2000000); ++$shift) {
|
1410 |
+
$msb <<= 1;
|
1411 |
+
}
|
1412 |
+
$x->_lshift($shift);
|
1413 |
+
$y->_lshift($shift);
|
1414 |
+
$y_value = &$y->value;
|
1415 |
+
|
1416 |
+
$x_max = count($x->value) - 1;
|
1417 |
+
$y_max = count($y->value) - 1;
|
1418 |
+
|
1419 |
+
$quotient = new Math_BigInteger();
|
1420 |
+
$quotient_value = &$quotient->value;
|
1421 |
+
$quotient_value = $this->_array_repeat(0, $x_max - $y_max + 1);
|
1422 |
+
|
1423 |
+
static $temp, $lhs, $rhs;
|
1424 |
+
if (!isset($temp)) {
|
1425 |
+
$temp = new Math_BigInteger();
|
1426 |
+
$lhs = new Math_BigInteger();
|
1427 |
+
$rhs = new Math_BigInteger();
|
1428 |
+
}
|
1429 |
+
$temp_value = &$temp->value;
|
1430 |
+
$rhs_value = &$rhs->value;
|
1431 |
+
|
1432 |
+
// $temp = $y << ($x_max - $y_max-1) in base 2**26
|
1433 |
+
$temp_value = array_merge($this->_array_repeat(0, $x_max - $y_max), $y_value);
|
1434 |
+
|
1435 |
+
while ( $x->compare($temp) >= 0 ) {
|
1436 |
+
// calculate the "common residue"
|
1437 |
+
++$quotient_value[$x_max - $y_max];
|
1438 |
+
$x = $x->subtract($temp);
|
1439 |
+
$x_max = count($x->value) - 1;
|
1440 |
+
}
|
1441 |
+
|
1442 |
+
for ($i = $x_max; $i >= $y_max + 1; --$i) {
|
1443 |
+
$x_value = &$x->value;
|
1444 |
+
$x_window = array(
|
1445 |
+
isset($x_value[$i]) ? $x_value[$i] : 0,
|
1446 |
+
isset($x_value[$i - 1]) ? $x_value[$i - 1] : 0,
|
1447 |
+
isset($x_value[$i - 2]) ? $x_value[$i - 2] : 0
|
1448 |
+
);
|
1449 |
+
$y_window = array(
|
1450 |
+
$y_value[$y_max],
|
1451 |
+
( $y_max > 0 ) ? $y_value[$y_max - 1] : 0
|
1452 |
+
);
|
1453 |
+
|
1454 |
+
$q_index = $i - $y_max - 1;
|
1455 |
+
if ($x_window[0] == $y_window[0]) {
|
1456 |
+
$quotient_value[$q_index] = 0x3FFFFFF;
|
1457 |
+
} else {
|
1458 |
+
$quotient_value[$q_index] = (int) (
|
1459 |
+
($x_window[0] * 0x4000000 + $x_window[1])
|
1460 |
+
/
|
1461 |
+
$y_window[0]
|
1462 |
+
);
|
1463 |
+
}
|
1464 |
+
|
1465 |
+
$temp_value = array($y_window[1], $y_window[0]);
|
1466 |
+
|
1467 |
+
$lhs->value = array($quotient_value[$q_index]);
|
1468 |
+
$lhs = $lhs->multiply($temp);
|
1469 |
+
|
1470 |
+
$rhs_value = array($x_window[2], $x_window[1], $x_window[0]);
|
1471 |
+
|
1472 |
+
while ( $lhs->compare($rhs) > 0 ) {
|
1473 |
+
--$quotient_value[$q_index];
|
1474 |
+
|
1475 |
+
$lhs->value = array($quotient_value[$q_index]);
|
1476 |
+
$lhs = $lhs->multiply($temp);
|
1477 |
+
}
|
1478 |
+
|
1479 |
+
$adjust = $this->_array_repeat(0, $q_index);
|
1480 |
+
$temp_value = array($quotient_value[$q_index]);
|
1481 |
+
$temp = $temp->multiply($y);
|
1482 |
+
$temp_value = &$temp->value;
|
1483 |
+
$temp_value = array_merge($adjust, $temp_value);
|
1484 |
+
|
1485 |
+
$x = $x->subtract($temp);
|
1486 |
+
|
1487 |
+
if ($x->compare($zero) < 0) {
|
1488 |
+
$temp_value = array_merge($adjust, $y_value);
|
1489 |
+
$x = $x->add($temp);
|
1490 |
+
|
1491 |
+
--$quotient_value[$q_index];
|
1492 |
+
}
|
1493 |
+
|
1494 |
+
$x_max = count($x_value) - 1;
|
1495 |
+
}
|
1496 |
+
|
1497 |
+
// unnormalize the remainder
|
1498 |
+
$x->_rshift($shift);
|
1499 |
+
|
1500 |
+
$quotient->is_negative = $x_sign != $y_sign;
|
1501 |
+
|
1502 |
+
// calculate the "common residue", if appropriate
|
1503 |
+
if ( $x_sign ) {
|
1504 |
+
$y->_rshift($shift);
|
1505 |
+
$x = $y->subtract($x);
|
1506 |
+
}
|
1507 |
+
|
1508 |
+
return array($this->_normalize($quotient), $this->_normalize($x));
|
1509 |
+
}
|
1510 |
+
|
1511 |
+
/**
|
1512 |
+
* Divides a BigInteger by a regular integer
|
1513 |
+
*
|
1514 |
+
* abc / x = a00 / x + b0 / x + c / x
|
1515 |
+
*
|
1516 |
+
* @param Array $dividend
|
1517 |
+
* @param Array $divisor
|
1518 |
+
* @return Array
|
1519 |
+
* @access private
|
1520 |
+
*/
|
1521 |
+
function _divide_digit($dividend, $divisor)
|
1522 |
+
{
|
1523 |
+
$carry = 0;
|
1524 |
+
$result = array();
|
1525 |
+
|
1526 |
+
for ($i = count($dividend) - 1; $i >= 0; --$i) {
|
1527 |
+
$temp = 0x4000000 * $carry + $dividend[$i];
|
1528 |
+
$result[$i] = (int) ($temp / $divisor);
|
1529 |
+
$carry = (int) ($temp - $divisor * $result[$i]);
|
1530 |
+
}
|
1531 |
+
|
1532 |
+
return array($result, $carry);
|
1533 |
+
}
|
1534 |
+
|
1535 |
+
/**
|
1536 |
+
* Performs modular exponentiation.
|
1537 |
+
*
|
1538 |
+
* Here's an example:
|
1539 |
+
* <code>
|
1540 |
+
* <?php
|
1541 |
+
* include('Math/BigInteger.php');
|
1542 |
+
*
|
1543 |
+
* $a = new Math_BigInteger('10');
|
1544 |
+
* $b = new Math_BigInteger('20');
|
1545 |
+
* $c = new Math_BigInteger('30');
|
1546 |
+
*
|
1547 |
+
* $c = $a->modPow($b, $c);
|
1548 |
+
*
|
1549 |
+
* echo $c->toString(); // outputs 10
|
1550 |
+
* ?>
|
1551 |
+
* </code>
|
1552 |
+
*
|
1553 |
+
* @param Math_BigInteger $e
|
1554 |
+
* @param Math_BigInteger $n
|
1555 |
+
* @return Math_BigInteger
|
1556 |
+
* @access public
|
1557 |
+
* @internal The most naive approach to modular exponentiation has very unreasonable requirements, and
|
1558 |
+
* and although the approach involving repeated squaring does vastly better, it, too, is impractical
|
1559 |
+
* for our purposes. The reason being that division - by far the most complicated and time-consuming
|
1560 |
+
* of the basic operations (eg. +,-,*,/) - occurs multiple times within it.
|
1561 |
+
*
|
1562 |
+
* Modular reductions resolve this issue. Although an individual modular reduction takes more time
|
1563 |
+
* then an individual division, when performed in succession (with the same modulo), they're a lot faster.
|
1564 |
+
*
|
1565 |
+
* The two most commonly used modular reductions are Barrett and Montgomery reduction. Montgomery reduction,
|
1566 |
+
* although faster, only works when the gcd of the modulo and of the base being used is 1. In RSA, when the
|
1567 |
+
* base is a power of two, the modulo - a product of two primes - is always going to have a gcd of 1 (because
|
1568 |
+
* the product of two odd numbers is odd), but what about when RSA isn't used?
|
1569 |
+
*
|
1570 |
+
* In contrast, Barrett reduction has no such constraint. As such, some bigint implementations perform a
|
1571 |
+
* Barrett reduction after every operation in the modpow function. Others perform Barrett reductions when the
|
1572 |
+
* modulo is even and Montgomery reductions when the modulo is odd. BigInteger.java's modPow method, however,
|
1573 |
+
* uses a trick involving the Chinese Remainder Theorem to factor the even modulo into two numbers - one odd and
|
1574 |
+
* the other, a power of two - and recombine them, later. This is the method that this modPow function uses.
|
1575 |
+
* {@link http://islab.oregonstate.edu/papers/j34monex.pdf Montgomery Reduction with Even Modulus} elaborates.
|
1576 |
+
*/
|
1577 |
+
function modPow($e, $n)
|
1578 |
+
{
|
1579 |
+
$n = $this->bitmask !== false && $this->bitmask->compare($n) < 0 ? $this->bitmask : $n->abs();
|
1580 |
+
|
1581 |
+
if ($e->compare(new Math_BigInteger()) < 0) {
|
1582 |
+
$e = $e->abs();
|
1583 |
+
|
1584 |
+
$temp = $this->modInverse($n);
|
1585 |
+
if ($temp === false) {
|
1586 |
+
return false;
|
1587 |
+
}
|
1588 |
+
|
1589 |
+
return $this->_normalize($temp->modPow($e, $n));
|
1590 |
+
}
|
1591 |
+
|
1592 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
1593 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
1594 |
+
$temp = new Math_BigInteger();
|
1595 |
+
$temp->value = gmp_powm($this->value, $e->value, $n->value);
|
1596 |
+
|
1597 |
+
return $this->_normalize($temp);
|
1598 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
1599 |
+
$temp = new Math_BigInteger();
|
1600 |
+
$temp->value = bcpowmod($this->value, $e->value, $n->value, 0);
|
1601 |
+
|
1602 |
+
return $this->_normalize($temp);
|
1603 |
+
}
|
1604 |
+
|
1605 |
+
if ( empty($e->value) ) {
|
1606 |
+
$temp = new Math_BigInteger();
|
1607 |
+
$temp->value = array(1);
|
1608 |
+
return $this->_normalize($temp);
|
1609 |
+
}
|
1610 |
+
|
1611 |
+
if ( $e->value == array(1) ) {
|
1612 |
+
list(, $temp) = $this->divide($n);
|
1613 |
+
return $this->_normalize($temp);
|
1614 |
+
}
|
1615 |
+
|
1616 |
+
if ( $e->value == array(2) ) {
|
1617 |
+
$temp = new Math_BigInteger();
|
1618 |
+
$temp->value = $this->_square($this->value);
|
1619 |
+
list(, $temp) = $temp->divide($n);
|
1620 |
+
return $this->_normalize($temp);
|
1621 |
+
}
|
1622 |
+
|
1623 |
+
return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_BARRETT));
|
1624 |
+
|
1625 |
+
// is the modulo odd?
|
1626 |
+
if ( $n->value[0] & 1 ) {
|
1627 |
+
return $this->_normalize($this->_slidingWindow($e, $n, MATH_BIGINTEGER_MONTGOMERY));
|
1628 |
+
}
|
1629 |
+
// if it's not, it's even
|
1630 |
+
|
1631 |
+
// find the lowest set bit (eg. the max pow of 2 that divides $n)
|
1632 |
+
for ($i = 0; $i < count($n->value); ++$i) {
|
1633 |
+
if ( $n->value[$i] ) {
|
1634 |
+
$temp = decbin($n->value[$i]);
|
1635 |
+
$j = strlen($temp) - strrpos($temp, '1') - 1;
|
1636 |
+
$j+= 26 * $i;
|
1637 |
+
break;
|
1638 |
+
}
|
1639 |
+
}
|
1640 |
+
// at this point, 2^$j * $n/(2^$j) == $n
|
1641 |
+
|
1642 |
+
$mod1 = $n->copy();
|
1643 |
+
$mod1->_rshift($j);
|
1644 |
+
$mod2 = new Math_BigInteger();
|
1645 |
+
$mod2->value = array(1);
|
1646 |
+
$mod2->_lshift($j);
|
1647 |
+
|
1648 |
+
$part1 = ( $mod1->value != array(1) ) ? $this->_slidingWindow($e, $mod1, MATH_BIGINTEGER_MONTGOMERY) : new Math_BigInteger();
|
1649 |
+
$part2 = $this->_slidingWindow($e, $mod2, MATH_BIGINTEGER_POWEROF2);
|
1650 |
+
|
1651 |
+
$y1 = $mod2->modInverse($mod1);
|
1652 |
+
$y2 = $mod1->modInverse($mod2);
|
1653 |
+
|
1654 |
+
$result = $part1->multiply($mod2);
|
1655 |
+
$result = $result->multiply($y1);
|
1656 |
+
|
1657 |
+
$temp = $part2->multiply($mod1);
|
1658 |
+
$temp = $temp->multiply($y2);
|
1659 |
+
|
1660 |
+
$result = $result->add($temp);
|
1661 |
+
list(, $result) = $result->divide($n);
|
1662 |
+
|
1663 |
+
return $this->_normalize($result);
|
1664 |
+
}
|
1665 |
+
|
1666 |
+
/**
|
1667 |
+
* Performs modular exponentiation.
|
1668 |
+
*
|
1669 |
+
* Alias for Math_BigInteger::modPow()
|
1670 |
+
*
|
1671 |
+
* @param Math_BigInteger $e
|
1672 |
+
* @param Math_BigInteger $n
|
1673 |
+
* @return Math_BigInteger
|
1674 |
+
* @access public
|
1675 |
+
*/
|
1676 |
+
function powMod($e, $n)
|
1677 |
+
{
|
1678 |
+
return $this->modPow($e, $n);
|
1679 |
+
}
|
1680 |
+
|
1681 |
+
/**
|
1682 |
+
* Sliding Window k-ary Modular Exponentiation
|
1683 |
+
*
|
1684 |
+
* Based on {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=27 HAC 14.85} /
|
1685 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=210 MPM 7.7}. In a departure from those algorithims,
|
1686 |
+
* however, this function performs a modular reduction after every multiplication and squaring operation.
|
1687 |
+
* As such, this function has the same preconditions that the reductions being used do.
|
1688 |
+
*
|
1689 |
+
* @param Math_BigInteger $e
|
1690 |
+
* @param Math_BigInteger $n
|
1691 |
+
* @param Integer $mode
|
1692 |
+
* @return Math_BigInteger
|
1693 |
+
* @access private
|
1694 |
+
*/
|
1695 |
+
function _slidingWindow($e, $n, $mode)
|
1696 |
+
{
|
1697 |
+
static $window_ranges = array(7, 25, 81, 241, 673, 1793); // from BigInteger.java's oddModPow function
|
1698 |
+
//static $window_ranges = array(0, 7, 36, 140, 450, 1303, 3529); // from MPM 7.3.1
|
1699 |
+
|
1700 |
+
$e_value = $e->value;
|
1701 |
+
$e_length = count($e_value) - 1;
|
1702 |
+
$e_bits = decbin($e_value[$e_length]);
|
1703 |
+
for ($i = $e_length - 1; $i >= 0; --$i) {
|
1704 |
+
$e_bits.= str_pad(decbin($e_value[$i]), 26, '0', STR_PAD_LEFT);
|
1705 |
+
}
|
1706 |
+
|
1707 |
+
$e_length = strlen($e_bits);
|
1708 |
+
|
1709 |
+
// calculate the appropriate window size.
|
1710 |
+
// $window_size == 3 if $window_ranges is between 25 and 81, for example.
|
1711 |
+
for ($i = 0, $window_size = 1; $e_length > $window_ranges[$i] && $i < count($window_ranges); ++$window_size, ++$i);
|
1712 |
+
|
1713 |
+
$n_value = $n->value;
|
1714 |
+
|
1715 |
+
// precompute $this^0 through $this^$window_size
|
1716 |
+
$powers = array();
|
1717 |
+
$powers[1] = $this->_prepareReduce($this->value, $n_value, $mode);
|
1718 |
+
$powers[2] = $this->_squareReduce($powers[1], $n_value, $mode);
|
1719 |
+
|
1720 |
+
// we do every other number since substr($e_bits, $i, $j+1) (see below) is supposed to end
|
1721 |
+
// in a 1. ie. it's supposed to be odd.
|
1722 |
+
$temp = 1 << ($window_size - 1);
|
1723 |
+
for ($i = 1; $i < $temp; ++$i) {
|
1724 |
+
$i2 = $i << 1;
|
1725 |
+
$powers[$i2 + 1] = $this->_multiplyReduce($powers[$i2 - 1], $powers[2], $n_value, $mode);
|
1726 |
+
}
|
1727 |
+
|
1728 |
+
$result = array(1);
|
1729 |
+
$result = $this->_prepareReduce($result, $n_value, $mode);
|
1730 |
+
|
1731 |
+
for ($i = 0; $i < $e_length; ) {
|
1732 |
+
if ( !$e_bits[$i] ) {
|
1733 |
+
$result = $this->_squareReduce($result, $n_value, $mode);
|
1734 |
+
++$i;
|
1735 |
+
} else {
|
1736 |
+
for ($j = $window_size - 1; $j > 0; --$j) {
|
1737 |
+
if ( !empty($e_bits[$i + $j]) ) {
|
1738 |
+
break;
|
1739 |
+
}
|
1740 |
+
}
|
1741 |
+
|
1742 |
+
for ($k = 0; $k <= $j; ++$k) {// eg. the length of substr($e_bits, $i, $j+1)
|
1743 |
+
$result = $this->_squareReduce($result, $n_value, $mode);
|
1744 |
+
}
|
1745 |
+
|
1746 |
+
$result = $this->_multiplyReduce($result, $powers[bindec(substr($e_bits, $i, $j + 1))], $n_value, $mode);
|
1747 |
+
|
1748 |
+
$i+=$j + 1;
|
1749 |
+
}
|
1750 |
+
}
|
1751 |
+
|
1752 |
+
$temp = new Math_BigInteger();
|
1753 |
+
$temp->value = $this->_reduce($result, $n_value, $mode);
|
1754 |
+
|
1755 |
+
return $temp;
|
1756 |
+
}
|
1757 |
+
|
1758 |
+
/**
|
1759 |
+
* Modular reduction
|
1760 |
+
*
|
1761 |
+
* For most $modes this will return the remainder.
|
1762 |
+
*
|
1763 |
+
* @see _slidingWindow()
|
1764 |
+
* @access private
|
1765 |
+
* @param Array $x
|
1766 |
+
* @param Array $n
|
1767 |
+
* @param Integer $mode
|
1768 |
+
* @return Array
|
1769 |
+
*/
|
1770 |
+
function _reduce($x, $n, $mode)
|
1771 |
+
{
|
1772 |
+
switch ($mode) {
|
1773 |
+
case MATH_BIGINTEGER_MONTGOMERY:
|
1774 |
+
return $this->_montgomery($x, $n);
|
1775 |
+
case MATH_BIGINTEGER_BARRETT:
|
1776 |
+
return $this->_barrett($x, $n);
|
1777 |
+
case MATH_BIGINTEGER_POWEROF2:
|
1778 |
+
$lhs = new Math_BigInteger();
|
1779 |
+
$lhs->value = $x;
|
1780 |
+
$rhs = new Math_BigInteger();
|
1781 |
+
$rhs->value = $n;
|
1782 |
+
return $x->_mod2($n);
|
1783 |
+
case MATH_BIGINTEGER_CLASSIC:
|
1784 |
+
$lhs = new Math_BigInteger();
|
1785 |
+
$lhs->value = $x;
|
1786 |
+
$rhs = new Math_BigInteger();
|
1787 |
+
$rhs->value = $n;
|
1788 |
+
list(, $temp) = $lhs->divide($rhs);
|
1789 |
+
return $temp->value;
|
1790 |
+
case MATH_BIGINTEGER_NONE:
|
1791 |
+
return $x;
|
1792 |
+
default:
|
1793 |
+
// an invalid $mode was provided
|
1794 |
+
}
|
1795 |
+
}
|
1796 |
+
|
1797 |
+
/**
|
1798 |
+
* Modular reduction preperation
|
1799 |
+
*
|
1800 |
+
* @see _slidingWindow()
|
1801 |
+
* @access private
|
1802 |
+
* @param Array $x
|
1803 |
+
* @param Array $n
|
1804 |
+
* @param Integer $mode
|
1805 |
+
* @return Array
|
1806 |
+
*/
|
1807 |
+
function _prepareReduce($x, $n, $mode)
|
1808 |
+
{
|
1809 |
+
if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
|
1810 |
+
return $this->_prepMontgomery($x, $n);
|
1811 |
+
}
|
1812 |
+
return $this->_reduce($x, $n, $mode);
|
1813 |
+
}
|
1814 |
+
|
1815 |
+
/**
|
1816 |
+
* Modular multiply
|
1817 |
+
*
|
1818 |
+
* @see _slidingWindow()
|
1819 |
+
* @access private
|
1820 |
+
* @param Array $x
|
1821 |
+
* @param Array $y
|
1822 |
+
* @param Array $n
|
1823 |
+
* @param Integer $mode
|
1824 |
+
* @return Array
|
1825 |
+
*/
|
1826 |
+
function _multiplyReduce($x, $y, $n, $mode)
|
1827 |
+
{
|
1828 |
+
if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
|
1829 |
+
return $this->_montgomeryMultiply($x, $y, $n);
|
1830 |
+
}
|
1831 |
+
$temp = $this->_multiply($x, false, $y, false);
|
1832 |
+
return $this->_reduce($temp[MATH_BIGINTEGER_VALUE], $n, $mode);
|
1833 |
+
}
|
1834 |
+
|
1835 |
+
/**
|
1836 |
+
* Modular square
|
1837 |
+
*
|
1838 |
+
* @see _slidingWindow()
|
1839 |
+
* @access private
|
1840 |
+
* @param Array $x
|
1841 |
+
* @param Array $n
|
1842 |
+
* @param Integer $mode
|
1843 |
+
* @return Array
|
1844 |
+
*/
|
1845 |
+
function _squareReduce($x, $n, $mode)
|
1846 |
+
{
|
1847 |
+
if ($mode == MATH_BIGINTEGER_MONTGOMERY) {
|
1848 |
+
return $this->_montgomeryMultiply($x, $x, $n);
|
1849 |
+
}
|
1850 |
+
return $this->_reduce($this->_square($x), $n, $mode);
|
1851 |
+
}
|
1852 |
+
|
1853 |
+
/**
|
1854 |
+
* Modulos for Powers of Two
|
1855 |
+
*
|
1856 |
+
* Calculates $x%$n, where $n = 2**$e, for some $e. Since this is basically the same as doing $x & ($n-1),
|
1857 |
+
* we'll just use this function as a wrapper for doing that.
|
1858 |
+
*
|
1859 |
+
* @see _slidingWindow()
|
1860 |
+
* @access private
|
1861 |
+
* @param Math_BigInteger
|
1862 |
+
* @return Math_BigInteger
|
1863 |
+
*/
|
1864 |
+
function _mod2($n)
|
1865 |
+
{
|
1866 |
+
$temp = new Math_BigInteger();
|
1867 |
+
$temp->value = array(1);
|
1868 |
+
return $this->bitwise_and($n->subtract($temp));
|
1869 |
+
}
|
1870 |
+
|
1871 |
+
/**
|
1872 |
+
* Barrett Modular Reduction
|
1873 |
+
*
|
1874 |
+
* See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=14 HAC 14.3.3} /
|
1875 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=165 MPM 6.2.5} for more information. Modified slightly,
|
1876 |
+
* so as not to require negative numbers (initially, this script didn't support negative numbers).
|
1877 |
+
*
|
1878 |
+
* Employs "folding", as described at
|
1879 |
+
* {@link http://www.cosic.esat.kuleuven.be/publications/thesis-149.pdf#page=66 thesis-149.pdf#page=66}. To quote from
|
1880 |
+
* it, "the idea [behind folding] is to find a value x' such that x (mod m) = x' (mod m), with x' being smaller than x."
|
1881 |
+
*
|
1882 |
+
* Unfortunately, the "Barrett Reduction with Folding" algorithm described in thesis-149.pdf is not, as written, all that
|
1883 |
+
* usable on account of (1) its not using reasonable radix points as discussed in
|
1884 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=162 MPM 6.2.2} and (2) the fact that, even with reasonable
|
1885 |
+
* radix points, it only works when there are an even number of digits in the denominator. The reason for (2) is that
|
1886 |
+
* (x >> 1) + (x >> 1) != x / 2 + x / 2. If x is even, they're the same, but if x is odd, they're not. See the in-line
|
1887 |
+
* comments for details.
|
1888 |
+
*
|
1889 |
+
* @see _slidingWindow()
|
1890 |
+
* @access private
|
1891 |
+
* @param Array $n
|
1892 |
+
* @param Array $m
|
1893 |
+
* @return Array
|
1894 |
+
*/
|
1895 |
+
function _barrett($n, $m)
|
1896 |
+
{
|
1897 |
+
static $cache = array(
|
1898 |
+
MATH_BIGINTEGER_VARIABLE => array(),
|
1899 |
+
MATH_BIGINTEGER_DATA => array()
|
1900 |
+
);
|
1901 |
+
|
1902 |
+
$m_length = count($m);
|
1903 |
+
|
1904 |
+
// if ($this->_compare($n, $this->_square($m)) >= 0) {
|
1905 |
+
if (count($n) > 2 * $m_length) {
|
1906 |
+
$lhs = new Math_BigInteger();
|
1907 |
+
$rhs = new Math_BigInteger();
|
1908 |
+
$lhs->value = $n;
|
1909 |
+
$rhs->value = $m;
|
1910 |
+
list(, $temp) = $lhs->divide($rhs);
|
1911 |
+
return $temp->value;
|
1912 |
+
}
|
1913 |
+
|
1914 |
+
// if (m.length >> 1) + 2 <= m.length then m is too small and n can't be reduced
|
1915 |
+
if ($m_length < 5) {
|
1916 |
+
return $this->_regularBarrett($n, $m);
|
1917 |
+
}
|
1918 |
+
|
1919 |
+
// n = 2 * m.length
|
1920 |
+
|
1921 |
+
if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
|
1922 |
+
$key = count($cache[MATH_BIGINTEGER_VARIABLE]);
|
1923 |
+
$cache[MATH_BIGINTEGER_VARIABLE][] = $m;
|
1924 |
+
|
1925 |
+
$lhs = new Math_BigInteger();
|
1926 |
+
$lhs_value = &$lhs->value;
|
1927 |
+
$lhs_value = $this->_array_repeat(0, $m_length + ($m_length >> 1));
|
1928 |
+
$lhs_value[] = 1;
|
1929 |
+
$rhs = new Math_BigInteger();
|
1930 |
+
$rhs->value = $m;
|
1931 |
+
|
1932 |
+
list($u, $m1) = $lhs->divide($rhs);
|
1933 |
+
$u = $u->value;
|
1934 |
+
$m1 = $m1->value;
|
1935 |
+
|
1936 |
+
$cache[MATH_BIGINTEGER_DATA][] = array(
|
1937 |
+
'u' => $u, // m.length >> 1 (technically (m.length >> 1) + 1)
|
1938 |
+
'm1'=> $m1 // m.length
|
1939 |
+
);
|
1940 |
+
} else {
|
1941 |
+
extract($cache[MATH_BIGINTEGER_DATA][$key]);
|
1942 |
+
}
|
1943 |
+
|
1944 |
+
$cutoff = $m_length + ($m_length >> 1);
|
1945 |
+
$lsd = array_slice($n, 0, $cutoff); // m.length + (m.length >> 1)
|
1946 |
+
$msd = array_slice($n, $cutoff); // m.length >> 1
|
1947 |
+
$lsd = $this->_trim($lsd);
|
1948 |
+
$temp = $this->_multiply($msd, false, $m1, false);
|
1949 |
+
$n = $this->_add($lsd, false, $temp[MATH_BIGINTEGER_VALUE], false); // m.length + (m.length >> 1) + 1
|
1950 |
+
|
1951 |
+
if ($m_length & 1) {
|
1952 |
+
return $this->_regularBarrett($n[MATH_BIGINTEGER_VALUE], $m);
|
1953 |
+
}
|
1954 |
+
|
1955 |
+
// (m.length + (m.length >> 1) + 1) - (m.length - 1) == (m.length >> 1) + 2
|
1956 |
+
$temp = array_slice($n[MATH_BIGINTEGER_VALUE], $m_length - 1);
|
1957 |
+
// if even: ((m.length >> 1) + 2) + (m.length >> 1) == m.length + 2
|
1958 |
+
// if odd: ((m.length >> 1) + 2) + (m.length >> 1) == (m.length - 1) + 2 == m.length + 1
|
1959 |
+
$temp = $this->_multiply($temp, false, $u, false);
|
1960 |
+
// if even: (m.length + 2) - ((m.length >> 1) + 1) = m.length - (m.length >> 1) + 1
|
1961 |
+
// if odd: (m.length + 1) - ((m.length >> 1) + 1) = m.length - (m.length >> 1)
|
1962 |
+
$temp = array_slice($temp[MATH_BIGINTEGER_VALUE], ($m_length >> 1) + 1);
|
1963 |
+
// if even: (m.length - (m.length >> 1) + 1) + m.length = 2 * m.length - (m.length >> 1) + 1
|
1964 |
+
// if odd: (m.length - (m.length >> 1)) + m.length = 2 * m.length - (m.length >> 1)
|
1965 |
+
$temp = $this->_multiply($temp, false, $m, false);
|
1966 |
+
|
1967 |
+
// at this point, if m had an odd number of digits, we'd be subtracting a 2 * m.length - (m.length >> 1) digit
|
1968 |
+
// number from a m.length + (m.length >> 1) + 1 digit number. ie. there'd be an extra digit and the while loop
|
1969 |
+
// following this comment would loop a lot (hence our calling _regularBarrett() in that situation).
|
1970 |
+
|
1971 |
+
$result = $this->_subtract($n[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
|
1972 |
+
|
1973 |
+
while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false) >= 0) {
|
1974 |
+
$result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $m, false);
|
1975 |
+
}
|
1976 |
+
|
1977 |
+
return $result[MATH_BIGINTEGER_VALUE];
|
1978 |
+
}
|
1979 |
+
|
1980 |
+
/**
|
1981 |
+
* (Regular) Barrett Modular Reduction
|
1982 |
+
*
|
1983 |
+
* For numbers with more than four digits Math_BigInteger::_barrett() is faster. The difference between that and this
|
1984 |
+
* is that this function does not fold the denominator into a smaller form.
|
1985 |
+
*
|
1986 |
+
* @see _slidingWindow()
|
1987 |
+
* @access private
|
1988 |
+
* @param Array $x
|
1989 |
+
* @param Array $n
|
1990 |
+
* @return Array
|
1991 |
+
*/
|
1992 |
+
function _regularBarrett($x, $n)
|
1993 |
+
{
|
1994 |
+
static $cache = array(
|
1995 |
+
MATH_BIGINTEGER_VARIABLE => array(),
|
1996 |
+
MATH_BIGINTEGER_DATA => array()
|
1997 |
+
);
|
1998 |
+
|
1999 |
+
$n_length = count($n);
|
2000 |
+
|
2001 |
+
if (count($x) > 2 * $n_length) {
|
2002 |
+
$lhs = new Math_BigInteger();
|
2003 |
+
$rhs = new Math_BigInteger();
|
2004 |
+
$lhs->value = $x;
|
2005 |
+
$rhs->value = $n;
|
2006 |
+
list(, $temp) = $lhs->divide($rhs);
|
2007 |
+
return $temp->value;
|
2008 |
+
}
|
2009 |
+
|
2010 |
+
if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
|
2011 |
+
$key = count($cache[MATH_BIGINTEGER_VARIABLE]);
|
2012 |
+
$cache[MATH_BIGINTEGER_VARIABLE][] = $n;
|
2013 |
+
$lhs = new Math_BigInteger();
|
2014 |
+
$lhs_value = &$lhs->value;
|
2015 |
+
$lhs_value = $this->_array_repeat(0, 2 * $n_length);
|
2016 |
+
$lhs_value[] = 1;
|
2017 |
+
$rhs = new Math_BigInteger();
|
2018 |
+
$rhs->value = $n;
|
2019 |
+
list($temp, ) = $lhs->divide($rhs); // m.length
|
2020 |
+
$cache[MATH_BIGINTEGER_DATA][] = $temp->value;
|
2021 |
+
}
|
2022 |
+
|
2023 |
+
// 2 * m.length - (m.length - 1) = m.length + 1
|
2024 |
+
$temp = array_slice($x, $n_length - 1);
|
2025 |
+
// (m.length + 1) + m.length = 2 * m.length + 1
|
2026 |
+
$temp = $this->_multiply($temp, false, $cache[MATH_BIGINTEGER_DATA][$key], false);
|
2027 |
+
// (2 * m.length + 1) - (m.length - 1) = m.length + 2
|
2028 |
+
$temp = array_slice($temp[MATH_BIGINTEGER_VALUE], $n_length + 1);
|
2029 |
+
|
2030 |
+
// m.length + 1
|
2031 |
+
$result = array_slice($x, 0, $n_length + 1);
|
2032 |
+
// m.length + 1
|
2033 |
+
$temp = $this->_multiplyLower($temp, false, $n, false, $n_length + 1);
|
2034 |
+
// $temp == array_slice($temp->_multiply($temp, false, $n, false)->value, 0, $n_length + 1)
|
2035 |
+
|
2036 |
+
if ($this->_compare($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]) < 0) {
|
2037 |
+
$corrector_value = $this->_array_repeat(0, $n_length + 1);
|
2038 |
+
$corrector_value[] = 1;
|
2039 |
+
$result = $this->_add($result, false, $corrector, false);
|
2040 |
+
$result = $result[MATH_BIGINTEGER_VALUE];
|
2041 |
+
}
|
2042 |
+
|
2043 |
+
// at this point, we're subtracting a number with m.length + 1 digits from another number with m.length + 1 digits
|
2044 |
+
$result = $this->_subtract($result, false, $temp[MATH_BIGINTEGER_VALUE], $temp[MATH_BIGINTEGER_SIGN]);
|
2045 |
+
while ($this->_compare($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false) > 0) {
|
2046 |
+
$result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], $result[MATH_BIGINTEGER_SIGN], $n, false);
|
2047 |
+
}
|
2048 |
+
|
2049 |
+
return $result[MATH_BIGINTEGER_VALUE];
|
2050 |
+
}
|
2051 |
+
|
2052 |
+
/**
|
2053 |
+
* Performs long multiplication up to $stop digits
|
2054 |
+
*
|
2055 |
+
* If you're going to be doing array_slice($product->value, 0, $stop), some cycles can be saved.
|
2056 |
+
*
|
2057 |
+
* @see _regularBarrett()
|
2058 |
+
* @param Array $x_value
|
2059 |
+
* @param Boolean $x_negative
|
2060 |
+
* @param Array $y_value
|
2061 |
+
* @param Boolean $y_negative
|
2062 |
+
* @return Array
|
2063 |
+
* @access private
|
2064 |
+
*/
|
2065 |
+
function _multiplyLower($x_value, $x_negative, $y_value, $y_negative, $stop)
|
2066 |
+
{
|
2067 |
+
$x_length = count($x_value);
|
2068 |
+
$y_length = count($y_value);
|
2069 |
+
|
2070 |
+
if ( !$x_length || !$y_length ) { // a 0 is being multiplied
|
2071 |
+
return array(
|
2072 |
+
MATH_BIGINTEGER_VALUE => array(),
|
2073 |
+
MATH_BIGINTEGER_SIGN => false
|
2074 |
+
);
|
2075 |
+
}
|
2076 |
+
|
2077 |
+
if ( $x_length < $y_length ) {
|
2078 |
+
$temp = $x_value;
|
2079 |
+
$x_value = $y_value;
|
2080 |
+
$y_value = $temp;
|
2081 |
+
|
2082 |
+
$x_length = count($x_value);
|
2083 |
+
$y_length = count($y_value);
|
2084 |
+
}
|
2085 |
+
|
2086 |
+
$product_value = $this->_array_repeat(0, $x_length + $y_length);
|
2087 |
+
|
2088 |
+
// the following for loop could be removed if the for loop following it
|
2089 |
+
// (the one with nested for loops) initially set $i to 0, but
|
2090 |
+
// doing so would also make the result in one set of unnecessary adds,
|
2091 |
+
// since on the outermost loops first pass, $product->value[$k] is going
|
2092 |
+
// to always be 0
|
2093 |
+
|
2094 |
+
$carry = 0;
|
2095 |
+
|
2096 |
+
for ($j = 0; $j < $x_length; ++$j) { // ie. $i = 0, $k = $i
|
2097 |
+
$temp = $x_value[$j] * $y_value[0] + $carry; // $product_value[$k] == 0
|
2098 |
+
$carry = (int) ($temp / 0x4000000);
|
2099 |
+
$product_value[$j] = (int) ($temp - 0x4000000 * $carry);
|
2100 |
+
}
|
2101 |
+
|
2102 |
+
if ($j < $stop) {
|
2103 |
+
$product_value[$j] = $carry;
|
2104 |
+
}
|
2105 |
+
|
2106 |
+
// the above for loop is what the previous comment was talking about. the
|
2107 |
+
// following for loop is the "one with nested for loops"
|
2108 |
+
|
2109 |
+
for ($i = 1; $i < $y_length; ++$i) {
|
2110 |
+
$carry = 0;
|
2111 |
+
|
2112 |
+
for ($j = 0, $k = $i; $j < $x_length && $k < $stop; ++$j, ++$k) {
|
2113 |
+
$temp = $product_value[$k] + $x_value[$j] * $y_value[$i] + $carry;
|
2114 |
+
$carry = (int) ($temp / 0x4000000);
|
2115 |
+
$product_value[$k] = (int) ($temp - 0x4000000 * $carry);
|
2116 |
+
}
|
2117 |
+
|
2118 |
+
if ($k < $stop) {
|
2119 |
+
$product_value[$k] = $carry;
|
2120 |
+
}
|
2121 |
+
}
|
2122 |
+
|
2123 |
+
return array(
|
2124 |
+
MATH_BIGINTEGER_VALUE => $this->_trim($product_value),
|
2125 |
+
MATH_BIGINTEGER_SIGN => $x_negative != $y_negative
|
2126 |
+
);
|
2127 |
+
}
|
2128 |
+
|
2129 |
+
/**
|
2130 |
+
* Montgomery Modular Reduction
|
2131 |
+
*
|
2132 |
+
* ($x->_prepMontgomery($n))->_montgomery($n) yields $x % $n.
|
2133 |
+
* {@link http://math.libtomcrypt.com/files/tommath.pdf#page=170 MPM 6.3} provides insights on how this can be
|
2134 |
+
* improved upon (basically, by using the comba method). gcd($n, 2) must be equal to one for this function
|
2135 |
+
* to work correctly.
|
2136 |
+
*
|
2137 |
+
* @see _prepMontgomery()
|
2138 |
+
* @see _slidingWindow()
|
2139 |
+
* @access private
|
2140 |
+
* @param Array $x
|
2141 |
+
* @param Array $n
|
2142 |
+
* @return Array
|
2143 |
+
*/
|
2144 |
+
function _montgomery($x, $n)
|
2145 |
+
{
|
2146 |
+
static $cache = array(
|
2147 |
+
MATH_BIGINTEGER_VARIABLE => array(),
|
2148 |
+
MATH_BIGINTEGER_DATA => array()
|
2149 |
+
);
|
2150 |
+
|
2151 |
+
if ( ($key = array_search($n, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
|
2152 |
+
$key = count($cache[MATH_BIGINTEGER_VARIABLE]);
|
2153 |
+
$cache[MATH_BIGINTEGER_VARIABLE][] = $x;
|
2154 |
+
$cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($n);
|
2155 |
+
}
|
2156 |
+
|
2157 |
+
$k = count($n);
|
2158 |
+
|
2159 |
+
$result = array(MATH_BIGINTEGER_VALUE => $x);
|
2160 |
+
|
2161 |
+
for ($i = 0; $i < $k; ++$i) {
|
2162 |
+
$temp = $result[MATH_BIGINTEGER_VALUE][$i] * $cache[MATH_BIGINTEGER_DATA][$key];
|
2163 |
+
$temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
|
2164 |
+
$temp = $this->_regularMultiply(array($temp), $n);
|
2165 |
+
$temp = array_merge($this->_array_repeat(0, $i), $temp);
|
2166 |
+
$result = $this->_add($result[MATH_BIGINTEGER_VALUE], false, $temp, false);
|
2167 |
+
}
|
2168 |
+
|
2169 |
+
$result[MATH_BIGINTEGER_VALUE] = array_slice($result[MATH_BIGINTEGER_VALUE], $k);
|
2170 |
+
|
2171 |
+
if ($this->_compare($result, false, $n, false) >= 0) {
|
2172 |
+
$result = $this->_subtract($result[MATH_BIGINTEGER_VALUE], false, $n, false);
|
2173 |
+
}
|
2174 |
+
|
2175 |
+
return $result[MATH_BIGINTEGER_VALUE];
|
2176 |
+
}
|
2177 |
+
|
2178 |
+
/**
|
2179 |
+
* Montgomery Multiply
|
2180 |
+
*
|
2181 |
+
* Interleaves the montgomery reduction and long multiplication algorithms together as described in
|
2182 |
+
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=13 HAC 14.36}
|
2183 |
+
*
|
2184 |
+
* @see _prepMontgomery()
|
2185 |
+
* @see _montgomery()
|
2186 |
+
* @access private
|
2187 |
+
* @param Array $x
|
2188 |
+
* @param Array $y
|
2189 |
+
* @param Array $m
|
2190 |
+
* @return Array
|
2191 |
+
*/
|
2192 |
+
function _montgomeryMultiply($x, $y, $m)
|
2193 |
+
{
|
2194 |
+
$temp = $this->_multiply($x, false, $y, false);
|
2195 |
+
return $this->_montgomery($temp[MATH_BIGINTEGER_VALUE], $m);
|
2196 |
+
|
2197 |
+
static $cache = array(
|
2198 |
+
MATH_BIGINTEGER_VARIABLE => array(),
|
2199 |
+
MATH_BIGINTEGER_DATA => array()
|
2200 |
+
);
|
2201 |
+
|
2202 |
+
if ( ($key = array_search($m, $cache[MATH_BIGINTEGER_VARIABLE])) === false ) {
|
2203 |
+
$key = count($cache[MATH_BIGINTEGER_VARIABLE]);
|
2204 |
+
$cache[MATH_BIGINTEGER_VARIABLE][] = $m;
|
2205 |
+
$cache[MATH_BIGINTEGER_DATA][] = $this->_modInverse67108864($m);
|
2206 |
+
}
|
2207 |
+
|
2208 |
+
$n = max(count($x), count($y), count($m));
|
2209 |
+
$x = array_pad($x, $n, 0);
|
2210 |
+
$y = array_pad($y, $n, 0);
|
2211 |
+
$m = array_pad($m, $n, 0);
|
2212 |
+
$a = array(MATH_BIGINTEGER_VALUE => $this->_array_repeat(0, $n + 1));
|
2213 |
+
for ($i = 0; $i < $n; ++$i) {
|
2214 |
+
$temp = $a[MATH_BIGINTEGER_VALUE][0] + $x[$i] * $y[0];
|
2215 |
+
$temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
|
2216 |
+
$temp = $temp * $cache[MATH_BIGINTEGER_DATA][$key];
|
2217 |
+
$temp = (int) ($temp - 0x4000000 * ((int) ($temp / 0x4000000)));
|
2218 |
+
$temp = $this->_add($this->_regularMultiply(array($x[$i]), $y), false, $this->_regularMultiply(array($temp), $m), false);
|
2219 |
+
$a = $this->_add($a[MATH_BIGINTEGER_VALUE], false, $temp[MATH_BIGINTEGER_VALUE], false);
|
2220 |
+
$a[MATH_BIGINTEGER_VALUE] = array_slice($a[MATH_BIGINTEGER_VALUE], 1);
|
2221 |
+
}
|
2222 |
+
if ($this->_compare($a[MATH_BIGINTEGER_VALUE], false, $m, false) >= 0) {
|
2223 |
+
$a = $this->_subtract($a[MATH_BIGINTEGER_VALUE], false, $m, false);
|
2224 |
+
}
|
2225 |
+
return $a[MATH_BIGINTEGER_VALUE];
|
2226 |
+
}
|
2227 |
+
|
2228 |
+
/**
|
2229 |
+
* Prepare a number for use in Montgomery Modular Reductions
|
2230 |
+
*
|
2231 |
+
* @see _montgomery()
|
2232 |
+
* @see _slidingWindow()
|
2233 |
+
* @access private
|
2234 |
+
* @param Array $x
|
2235 |
+
* @param Array $n
|
2236 |
+
* @return Array
|
2237 |
+
*/
|
2238 |
+
function _prepMontgomery($x, $n)
|
2239 |
+
{
|
2240 |
+
$lhs = new Math_BigInteger();
|
2241 |
+
$lhs->value = array_merge($this->_array_repeat(0, count($n)), $x);
|
2242 |
+
$rhs = new Math_BigInteger();
|
2243 |
+
$rhs->value = $n;
|
2244 |
+
|
2245 |
+
list(, $temp) = $lhs->divide($rhs);
|
2246 |
+
return $temp->value;
|
2247 |
+
}
|
2248 |
+
|
2249 |
+
/**
|
2250 |
+
* Modular Inverse of a number mod 2**26 (eg. 67108864)
|
2251 |
+
*
|
2252 |
+
* Based off of the bnpInvDigit function implemented and justified in the following URL:
|
2253 |
+
*
|
2254 |
+
* {@link http://www-cs-students.stanford.edu/~tjw/jsbn/jsbn.js}
|
2255 |
+
*
|
2256 |
+
* The following URL provides more info:
|
2257 |
+
*
|
2258 |
+
* {@link http://groups.google.com/group/sci.crypt/msg/7a137205c1be7d85}
|
2259 |
+
*
|
2260 |
+
* As for why we do all the bitmasking... strange things can happen when converting from floats to ints. For
|
2261 |
+
* instance, on some computers, var_dump((int) -4294967297) yields int(-1) and on others, it yields
|
2262 |
+
* int(-2147483648). To avoid problems stemming from this, we use bitmasks to guarantee that ints aren't
|
2263 |
+
* auto-converted to floats. The outermost bitmask is present because without it, there's no guarantee that
|
2264 |
+
* the "residue" returned would be the so-called "common residue". We use fmod, in the last step, because the
|
2265 |
+
* maximum possible $x is 26 bits and the maximum $result is 16 bits. Thus, we have to be able to handle up to
|
2266 |
+
* 40 bits, which only 64-bit floating points will support.
|
2267 |
+
*
|
2268 |
+
* Thanks to Pedro Gimeno Fortea for input!
|
2269 |
+
*
|
2270 |
+
* @see _montgomery()
|
2271 |
+
* @access private
|
2272 |
+
* @param Array $x
|
2273 |
+
* @return Integer
|
2274 |
+
*/
|
2275 |
+
function _modInverse67108864($x) // 2**26 == 67108864
|
2276 |
+
{
|
2277 |
+
$x = -$x[0];
|
2278 |
+
$result = $x & 0x3; // x**-1 mod 2**2
|
2279 |
+
$result = ($result * (2 - $x * $result)) & 0xF; // x**-1 mod 2**4
|
2280 |
+
$result = ($result * (2 - ($x & 0xFF) * $result)) & 0xFF; // x**-1 mod 2**8
|
2281 |
+
$result = ($result * ((2 - ($x & 0xFFFF) * $result) & 0xFFFF)) & 0xFFFF; // x**-1 mod 2**16
|
2282 |
+
$result = fmod($result * (2 - fmod($x * $result, 0x4000000)), 0x4000000); // x**-1 mod 2**26
|
2283 |
+
return $result & 0x3FFFFFF;
|
2284 |
+
}
|
2285 |
+
|
2286 |
+
/**
|
2287 |
+
* Calculates modular inverses.
|
2288 |
+
*
|
2289 |
+
* Say you have (30 mod 17 * x mod 17) mod 17 == 1. x can be found using modular inverses.
|
2290 |
+
*
|
2291 |
+
* Here's an example:
|
2292 |
+
* <code>
|
2293 |
+
* <?php
|
2294 |
+
* include('Math/BigInteger.php');
|
2295 |
+
*
|
2296 |
+
* $a = new Math_BigInteger(30);
|
2297 |
+
* $b = new Math_BigInteger(17);
|
2298 |
+
*
|
2299 |
+
* $c = $a->modInverse($b);
|
2300 |
+
* echo $c->toString(); // outputs 4
|
2301 |
+
*
|
2302 |
+
* echo "\r\n";
|
2303 |
+
*
|
2304 |
+
* $d = $a->multiply($c);
|
2305 |
+
* list(, $d) = $d->divide($b);
|
2306 |
+
* echo $d; // outputs 1 (as per the definition of modular inverse)
|
2307 |
+
* ?>
|
2308 |
+
* </code>
|
2309 |
+
*
|
2310 |
+
* @param Math_BigInteger $n
|
2311 |
+
* @return mixed false, if no modular inverse exists, Math_BigInteger, otherwise.
|
2312 |
+
* @access public
|
2313 |
+
* @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=21 HAC 14.64} for more information.
|
2314 |
+
*/
|
2315 |
+
function modInverse($n)
|
2316 |
+
{
|
2317 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
2318 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
2319 |
+
$temp = new Math_BigInteger();
|
2320 |
+
$temp->value = gmp_invert($this->value, $n->value);
|
2321 |
+
|
2322 |
+
return ( $temp->value === false ) ? false : $this->_normalize($temp);
|
2323 |
+
}
|
2324 |
+
|
2325 |
+
static $zero, $one;
|
2326 |
+
if (!isset($zero)) {
|
2327 |
+
$zero = new Math_BigInteger();
|
2328 |
+
$one = new Math_BigInteger(1);
|
2329 |
+
}
|
2330 |
+
|
2331 |
+
// $x mod $n == $x mod -$n.
|
2332 |
+
$n = $n->abs();
|
2333 |
+
|
2334 |
+
if ($this->compare($zero) < 0) {
|
2335 |
+
$temp = $this->abs();
|
2336 |
+
$temp = $temp->modInverse($n);
|
2337 |
+
return $negated === false ? false : $this->_normalize($n->subtract($temp));
|
2338 |
+
}
|
2339 |
+
|
2340 |
+
extract($this->extendedGCD($n));
|
2341 |
+
|
2342 |
+
if (!$gcd->equals($one)) {
|
2343 |
+
return false;
|
2344 |
+
}
|
2345 |
+
|
2346 |
+
$x = $x->compare($zero) < 0 ? $x->add($n) : $x;
|
2347 |
+
|
2348 |
+
return $this->compare($zero) < 0 ? $this->_normalize($n->subtract($x)) : $this->_normalize($x);
|
2349 |
+
}
|
2350 |
+
|
2351 |
+
/**
|
2352 |
+
* Calculates the greatest common divisor and B�zout's identity.
|
2353 |
+
*
|
2354 |
+
* Say you have 693 and 609. The GCD is 21. B�zout's identity states that there exist integers x and y such that
|
2355 |
+
* 693*x + 609*y == 21. In point of fact, there are actually an infinite number of x and y combinations and which
|
2356 |
+
* combination is returned is dependant upon which mode is in use. See
|
2357 |
+
* {@link http://en.wikipedia.org/wiki/B%C3%A9zout%27s_identity B�zout's identity - Wikipedia} for more information.
|
2358 |
+
*
|
2359 |
+
* Here's an example:
|
2360 |
+
* <code>
|
2361 |
+
* <?php
|
2362 |
+
* include('Math/BigInteger.php');
|
2363 |
+
*
|
2364 |
+
* $a = new Math_BigInteger(693);
|
2365 |
+
* $b = new Math_BigInteger(609);
|
2366 |
+
*
|
2367 |
+
* extract($a->extendedGCD($b));
|
2368 |
+
*
|
2369 |
+
* echo $gcd->toString() . "\r\n"; // outputs 21
|
2370 |
+
* echo $a->toString() * $x->toString() + $b->toString() * $y->toString(); // outputs 21
|
2371 |
+
* ?>
|
2372 |
+
* </code>
|
2373 |
+
*
|
2374 |
+
* @param Math_BigInteger $n
|
2375 |
+
* @return Math_BigInteger
|
2376 |
+
* @access public
|
2377 |
+
* @internal Calculates the GCD using the binary xGCD algorithim described in
|
2378 |
+
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap14.pdf#page=19 HAC 14.61}. As the text above 14.61 notes,
|
2379 |
+
* the more traditional algorithim requires "relatively costly multiple-precision divisions".
|
2380 |
+
*/
|
2381 |
+
function extendedGCD($n)
|
2382 |
+
{
|
2383 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
2384 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
2385 |
+
extract(gmp_gcdext($this->value, $n->value));
|
2386 |
+
|
2387 |
+
return array(
|
2388 |
+
'gcd' => $this->_normalize(new Math_BigInteger($g)),
|
2389 |
+
'x' => $this->_normalize(new Math_BigInteger($s)),
|
2390 |
+
'y' => $this->_normalize(new Math_BigInteger($t))
|
2391 |
+
);
|
2392 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
2393 |
+
// it might be faster to use the binary xGCD algorithim here, as well, but (1) that algorithim works
|
2394 |
+
// best when the base is a power of 2 and (2) i don't think it'd make much difference, anyway. as is,
|
2395 |
+
// the basic extended euclidean algorithim is what we're using.
|
2396 |
+
|
2397 |
+
$u = $this->value;
|
2398 |
+
$v = $n->value;
|
2399 |
+
|
2400 |
+
$a = '1';
|
2401 |
+
$b = '0';
|
2402 |
+
$c = '0';
|
2403 |
+
$d = '1';
|
2404 |
+
|
2405 |
+
while (bccomp($v, '0', 0) != 0) {
|
2406 |
+
$q = bcdiv($u, $v, 0);
|
2407 |
+
|
2408 |
+
$temp = $u;
|
2409 |
+
$u = $v;
|
2410 |
+
$v = bcsub($temp, bcmul($v, $q, 0), 0);
|
2411 |
+
|
2412 |
+
$temp = $a;
|
2413 |
+
$a = $c;
|
2414 |
+
$c = bcsub($temp, bcmul($a, $q, 0), 0);
|
2415 |
+
|
2416 |
+
$temp = $b;
|
2417 |
+
$b = $d;
|
2418 |
+
$d = bcsub($temp, bcmul($b, $q, 0), 0);
|
2419 |
+
}
|
2420 |
+
|
2421 |
+
return array(
|
2422 |
+
'gcd' => $this->_normalize(new Math_BigInteger($u)),
|
2423 |
+
'x' => $this->_normalize(new Math_BigInteger($a)),
|
2424 |
+
'y' => $this->_normalize(new Math_BigInteger($b))
|
2425 |
+
);
|
2426 |
+
}
|
2427 |
+
|
2428 |
+
$y = $n->copy();
|
2429 |
+
$x = $this->copy();
|
2430 |
+
$g = new Math_BigInteger();
|
2431 |
+
$g->value = array(1);
|
2432 |
+
|
2433 |
+
while ( !(($x->value[0] & 1)|| ($y->value[0] & 1)) ) {
|
2434 |
+
$x->_rshift(1);
|
2435 |
+
$y->_rshift(1);
|
2436 |
+
$g->_lshift(1);
|
2437 |
+
}
|
2438 |
+
|
2439 |
+
$u = $x->copy();
|
2440 |
+
$v = $y->copy();
|
2441 |
+
|
2442 |
+
$a = new Math_BigInteger();
|
2443 |
+
$b = new Math_BigInteger();
|
2444 |
+
$c = new Math_BigInteger();
|
2445 |
+
$d = new Math_BigInteger();
|
2446 |
+
|
2447 |
+
$a->value = $d->value = $g->value = array(1);
|
2448 |
+
$b->value = $c->value = array();
|
2449 |
+
|
2450 |
+
while ( !empty($u->value) ) {
|
2451 |
+
while ( !($u->value[0] & 1) ) {
|
2452 |
+
$u->_rshift(1);
|
2453 |
+
if ( (!empty($a->value) && ($a->value[0] & 1)) || (!empty($b->value) && ($b->value[0] & 1)) ) {
|
2454 |
+
$a = $a->add($y);
|
2455 |
+
$b = $b->subtract($x);
|
2456 |
+
}
|
2457 |
+
$a->_rshift(1);
|
2458 |
+
$b->_rshift(1);
|
2459 |
+
}
|
2460 |
+
|
2461 |
+
while ( !($v->value[0] & 1) ) {
|
2462 |
+
$v->_rshift(1);
|
2463 |
+
if ( (!empty($d->value) && ($d->value[0] & 1)) || (!empty($c->value) && ($c->value[0] & 1)) ) {
|
2464 |
+
$c = $c->add($y);
|
2465 |
+
$d = $d->subtract($x);
|
2466 |
+
}
|
2467 |
+
$c->_rshift(1);
|
2468 |
+
$d->_rshift(1);
|
2469 |
+
}
|
2470 |
+
|
2471 |
+
if ($u->compare($v) >= 0) {
|
2472 |
+
$u = $u->subtract($v);
|
2473 |
+
$a = $a->subtract($c);
|
2474 |
+
$b = $b->subtract($d);
|
2475 |
+
} else {
|
2476 |
+
$v = $v->subtract($u);
|
2477 |
+
$c = $c->subtract($a);
|
2478 |
+
$d = $d->subtract($b);
|
2479 |
+
}
|
2480 |
+
}
|
2481 |
+
|
2482 |
+
return array(
|
2483 |
+
'gcd' => $this->_normalize($g->multiply($v)),
|
2484 |
+
'x' => $this->_normalize($c),
|
2485 |
+
'y' => $this->_normalize($d)
|
2486 |
+
);
|
2487 |
+
}
|
2488 |
+
|
2489 |
+
/**
|
2490 |
+
* Calculates the greatest common divisor
|
2491 |
+
*
|
2492 |
+
* Say you have 693 and 609. The GCD is 21.
|
2493 |
+
*
|
2494 |
+
* Here's an example:
|
2495 |
+
* <code>
|
2496 |
+
* <?php
|
2497 |
+
* include('Math/BigInteger.php');
|
2498 |
+
*
|
2499 |
+
* $a = new Math_BigInteger(693);
|
2500 |
+
* $b = new Math_BigInteger(609);
|
2501 |
+
*
|
2502 |
+
* $gcd = a->extendedGCD($b);
|
2503 |
+
*
|
2504 |
+
* echo $gcd->toString() . "\r\n"; // outputs 21
|
2505 |
+
* ?>
|
2506 |
+
* </code>
|
2507 |
+
*
|
2508 |
+
* @param Math_BigInteger $n
|
2509 |
+
* @return Math_BigInteger
|
2510 |
+
* @access public
|
2511 |
+
*/
|
2512 |
+
function gcd($n)
|
2513 |
+
{
|
2514 |
+
extract($this->extendedGCD($n));
|
2515 |
+
return $gcd;
|
2516 |
+
}
|
2517 |
+
|
2518 |
+
/**
|
2519 |
+
* Absolute value.
|
2520 |
+
*
|
2521 |
+
* @return Math_BigInteger
|
2522 |
+
* @access public
|
2523 |
+
*/
|
2524 |
+
function abs()
|
2525 |
+
{
|
2526 |
+
$temp = new Math_BigInteger();
|
2527 |
+
|
2528 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
2529 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
2530 |
+
$temp->value = gmp_abs($this->value);
|
2531 |
+
break;
|
2532 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
2533 |
+
$temp->value = (bccomp($this->value, '0', 0) < 0) ? substr($this->value, 1) : $this->value;
|
2534 |
+
break;
|
2535 |
+
default:
|
2536 |
+
$temp->value = $this->value;
|
2537 |
+
}
|
2538 |
+
|
2539 |
+
return $temp;
|
2540 |
+
}
|
2541 |
+
|
2542 |
+
/**
|
2543 |
+
* Compares two numbers.
|
2544 |
+
*
|
2545 |
+
* Although one might think !$x->compare($y) means $x != $y, it, in fact, means the opposite. The reason for this is
|
2546 |
+
* demonstrated thusly:
|
2547 |
+
*
|
2548 |
+
* $x > $y: $x->compare($y) > 0
|
2549 |
+
* $x < $y: $x->compare($y) < 0
|
2550 |
+
* $x == $y: $x->compare($y) == 0
|
2551 |
+
*
|
2552 |
+
* Note how the same comparison operator is used. If you want to test for equality, use $x->equals($y).
|
2553 |
+
*
|
2554 |
+
* @param Math_BigInteger $x
|
2555 |
+
* @return Integer < 0 if $this is less than $x; > 0 if $this is greater than $x, and 0 if they are equal.
|
2556 |
+
* @access public
|
2557 |
+
* @see equals()
|
2558 |
+
* @internal Could return $this->subtract($x), but that's not as fast as what we do do.
|
2559 |
+
*/
|
2560 |
+
function compare($y)
|
2561 |
+
{
|
2562 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
2563 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
2564 |
+
return gmp_cmp($this->value, $y->value);
|
2565 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
2566 |
+
return bccomp($this->value, $y->value, 0);
|
2567 |
+
}
|
2568 |
+
|
2569 |
+
return $this->_compare($this->value, $this->is_negative, $y->value, $y->is_negative);
|
2570 |
+
}
|
2571 |
+
|
2572 |
+
/**
|
2573 |
+
* Compares two numbers.
|
2574 |
+
*
|
2575 |
+
* @param Array $x_value
|
2576 |
+
* @param Boolean $x_negative
|
2577 |
+
* @param Array $y_value
|
2578 |
+
* @param Boolean $y_negative
|
2579 |
+
* @return Integer
|
2580 |
+
* @see compare()
|
2581 |
+
* @access private
|
2582 |
+
*/
|
2583 |
+
function _compare($x_value, $x_negative, $y_value, $y_negative)
|
2584 |
+
{
|
2585 |
+
if ( $x_negative != $y_negative ) {
|
2586 |
+
return ( !$x_negative && $y_negative ) ? 1 : -1;
|
2587 |
+
}
|
2588 |
+
|
2589 |
+
$result = $x_negative ? -1 : 1;
|
2590 |
+
|
2591 |
+
if ( count($x_value) != count($y_value) ) {
|
2592 |
+
return ( count($x_value) > count($y_value) ) ? $result : -$result;
|
2593 |
+
}
|
2594 |
+
$size = max(count($x_value), count($y_value));
|
2595 |
+
|
2596 |
+
$x_value = array_pad($x_value, $size, 0);
|
2597 |
+
$y_value = array_pad($y_value, $size, 0);
|
2598 |
+
|
2599 |
+
for ($i = count($x_value) - 1; $i >= 0; --$i) {
|
2600 |
+
if ($x_value[$i] != $y_value[$i]) {
|
2601 |
+
return ( $x_value[$i] > $y_value[$i] ) ? $result : -$result;
|
2602 |
+
}
|
2603 |
+
}
|
2604 |
+
|
2605 |
+
return 0;
|
2606 |
+
}
|
2607 |
+
|
2608 |
+
/**
|
2609 |
+
* Tests the equality of two numbers.
|
2610 |
+
*
|
2611 |
+
* If you need to see if one number is greater than or less than another number, use Math_BigInteger::compare()
|
2612 |
+
*
|
2613 |
+
* @param Math_BigInteger $x
|
2614 |
+
* @return Boolean
|
2615 |
+
* @access public
|
2616 |
+
* @see compare()
|
2617 |
+
*/
|
2618 |
+
function equals($x)
|
2619 |
+
{
|
2620 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
2621 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
2622 |
+
return gmp_cmp($this->value, $x->value) == 0;
|
2623 |
+
default:
|
2624 |
+
return $this->value === $x->value && $this->is_negative == $x->is_negative;
|
2625 |
+
}
|
2626 |
+
}
|
2627 |
+
|
2628 |
+
/**
|
2629 |
+
* Set Precision
|
2630 |
+
*
|
2631 |
+
* Some bitwise operations give different results depending on the precision being used. Examples include left
|
2632 |
+
* shift, not, and rotates.
|
2633 |
+
*
|
2634 |
+
* @param Math_BigInteger $x
|
2635 |
+
* @access public
|
2636 |
+
* @return Math_BigInteger
|
2637 |
+
*/
|
2638 |
+
function setPrecision($bits)
|
2639 |
+
{
|
2640 |
+
$this->precision = $bits;
|
2641 |
+
if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ) {
|
2642 |
+
$this->bitmask = new Math_BigInteger(chr((1 << ($bits & 0x7)) - 1) . str_repeat(chr(0xFF), $bits >> 3), 256);
|
2643 |
+
} else {
|
2644 |
+
$this->bitmask = new Math_BigInteger(bcpow('2', $bits, 0));
|
2645 |
+
}
|
2646 |
+
|
2647 |
+
$temp = $this->_normalize($this);
|
2648 |
+
$this->value = $temp->value;
|
2649 |
+
}
|
2650 |
+
|
2651 |
+
/**
|
2652 |
+
* Logical And
|
2653 |
+
*
|
2654 |
+
* @param Math_BigInteger $x
|
2655 |
+
* @access public
|
2656 |
+
* @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
|
2657 |
+
* @return Math_BigInteger
|
2658 |
+
*/
|
2659 |
+
function bitwise_and($x)
|
2660 |
+
{
|
2661 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
2662 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
2663 |
+
$temp = new Math_BigInteger();
|
2664 |
+
$temp->value = gmp_and($this->value, $x->value);
|
2665 |
+
|
2666 |
+
return $this->_normalize($temp);
|
2667 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
2668 |
+
$left = $this->toBytes();
|
2669 |
+
$right = $x->toBytes();
|
2670 |
+
|
2671 |
+
$length = max(strlen($left), strlen($right));
|
2672 |
+
|
2673 |
+
$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
|
2674 |
+
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
|
2675 |
+
|
2676 |
+
return $this->_normalize(new Math_BigInteger($left & $right, 256));
|
2677 |
+
}
|
2678 |
+
|
2679 |
+
$result = $this->copy();
|
2680 |
+
|
2681 |
+
$length = min(count($x->value), count($this->value));
|
2682 |
+
|
2683 |
+
$result->value = array_slice($result->value, 0, $length);
|
2684 |
+
|
2685 |
+
for ($i = 0; $i < $length; ++$i) {
|
2686 |
+
$result->value[$i] = $result->value[$i] & $x->value[$i];
|
2687 |
+
}
|
2688 |
+
|
2689 |
+
return $this->_normalize($result);
|
2690 |
+
}
|
2691 |
+
|
2692 |
+
/**
|
2693 |
+
* Logical Or
|
2694 |
+
*
|
2695 |
+
* @param Math_BigInteger $x
|
2696 |
+
* @access public
|
2697 |
+
* @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
|
2698 |
+
* @return Math_BigInteger
|
2699 |
+
*/
|
2700 |
+
function bitwise_or($x)
|
2701 |
+
{
|
2702 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
2703 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
2704 |
+
$temp = new Math_BigInteger();
|
2705 |
+
$temp->value = gmp_or($this->value, $x->value);
|
2706 |
+
|
2707 |
+
return $this->_normalize($temp);
|
2708 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
2709 |
+
$left = $this->toBytes();
|
2710 |
+
$right = $x->toBytes();
|
2711 |
+
|
2712 |
+
$length = max(strlen($left), strlen($right));
|
2713 |
+
|
2714 |
+
$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
|
2715 |
+
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
|
2716 |
+
|
2717 |
+
return $this->_normalize(new Math_BigInteger($left | $right, 256));
|
2718 |
+
}
|
2719 |
+
|
2720 |
+
$length = max(count($this->value), count($x->value));
|
2721 |
+
$result = $this->copy();
|
2722 |
+
$result->value = array_pad($result->value, 0, $length);
|
2723 |
+
$x->value = array_pad($x->value, 0, $length);
|
2724 |
+
|
2725 |
+
for ($i = 0; $i < $length; ++$i) {
|
2726 |
+
$result->value[$i] = $this->value[$i] | $x->value[$i];
|
2727 |
+
}
|
2728 |
+
|
2729 |
+
return $this->_normalize($result);
|
2730 |
+
}
|
2731 |
+
|
2732 |
+
/**
|
2733 |
+
* Logical Exclusive-Or
|
2734 |
+
*
|
2735 |
+
* @param Math_BigInteger $x
|
2736 |
+
* @access public
|
2737 |
+
* @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
|
2738 |
+
* @return Math_BigInteger
|
2739 |
+
*/
|
2740 |
+
function bitwise_xor($x)
|
2741 |
+
{
|
2742 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
2743 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
2744 |
+
$temp = new Math_BigInteger();
|
2745 |
+
$temp->value = gmp_xor($this->value, $x->value);
|
2746 |
+
|
2747 |
+
return $this->_normalize($temp);
|
2748 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
2749 |
+
$left = $this->toBytes();
|
2750 |
+
$right = $x->toBytes();
|
2751 |
+
|
2752 |
+
$length = max(strlen($left), strlen($right));
|
2753 |
+
|
2754 |
+
$left = str_pad($left, $length, chr(0), STR_PAD_LEFT);
|
2755 |
+
$right = str_pad($right, $length, chr(0), STR_PAD_LEFT);
|
2756 |
+
|
2757 |
+
return $this->_normalize(new Math_BigInteger($left ^ $right, 256));
|
2758 |
+
}
|
2759 |
+
|
2760 |
+
$length = max(count($this->value), count($x->value));
|
2761 |
+
$result = $this->copy();
|
2762 |
+
$result->value = array_pad($result->value, 0, $length);
|
2763 |
+
$x->value = array_pad($x->value, 0, $length);
|
2764 |
+
|
2765 |
+
for ($i = 0; $i < $length; ++$i) {
|
2766 |
+
$result->value[$i] = $this->value[$i] ^ $x->value[$i];
|
2767 |
+
}
|
2768 |
+
|
2769 |
+
return $this->_normalize($result);
|
2770 |
+
}
|
2771 |
+
|
2772 |
+
/**
|
2773 |
+
* Logical Not
|
2774 |
+
*
|
2775 |
+
* @access public
|
2776 |
+
* @internal Implemented per a request by Lluis Pamies i Juarez <lluis _a_ pamies.cat>
|
2777 |
+
* @return Math_BigInteger
|
2778 |
+
*/
|
2779 |
+
function bitwise_not()
|
2780 |
+
{
|
2781 |
+
// calculuate "not" without regard to $this->precision
|
2782 |
+
// (will always result in a smaller number. ie. ~1 isn't 1111 1110 - it's 0)
|
2783 |
+
$temp = $this->toBytes();
|
2784 |
+
$pre_msb = decbin(ord($temp[0]));
|
2785 |
+
$temp = ~$temp;
|
2786 |
+
$msb = decbin(ord($temp[0]));
|
2787 |
+
if (strlen($msb) == 8) {
|
2788 |
+
$msb = substr($msb, strpos($msb, '0'));
|
2789 |
+
}
|
2790 |
+
$temp[0] = chr(bindec($msb));
|
2791 |
+
|
2792 |
+
// see if we need to add extra leading 1's
|
2793 |
+
$current_bits = strlen($pre_msb) + 8 * strlen($temp) - 8;
|
2794 |
+
$new_bits = $this->precision - $current_bits;
|
2795 |
+
if ($new_bits <= 0) {
|
2796 |
+
return $this->_normalize(new Math_BigInteger($temp, 256));
|
2797 |
+
}
|
2798 |
+
|
2799 |
+
// generate as many leading 1's as we need to.
|
2800 |
+
$leading_ones = chr((1 << ($new_bits & 0x7)) - 1) . str_repeat(chr(0xFF), $new_bits >> 3);
|
2801 |
+
$this->_base256_lshift($leading_ones, $current_bits);
|
2802 |
+
|
2803 |
+
$temp = str_pad($temp, ceil($this->bits / 8), chr(0), STR_PAD_LEFT);
|
2804 |
+
|
2805 |
+
return $this->_normalize(new Math_BigInteger($leading_ones | $temp, 256));
|
2806 |
+
}
|
2807 |
+
|
2808 |
+
/**
|
2809 |
+
* Logical Right Shift
|
2810 |
+
*
|
2811 |
+
* Shifts BigInteger's by $shift bits, effectively dividing by 2**$shift.
|
2812 |
+
*
|
2813 |
+
* @param Integer $shift
|
2814 |
+
* @return Math_BigInteger
|
2815 |
+
* @access public
|
2816 |
+
* @internal The only version that yields any speed increases is the internal version.
|
2817 |
+
*/
|
2818 |
+
function bitwise_rightShift($shift)
|
2819 |
+
{
|
2820 |
+
$temp = new Math_BigInteger();
|
2821 |
+
|
2822 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
2823 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
2824 |
+
static $two;
|
2825 |
+
|
2826 |
+
if (!isset($two)) {
|
2827 |
+
$two = gmp_init('2');
|
2828 |
+
}
|
2829 |
+
|
2830 |
+
$temp->value = gmp_div_q($this->value, gmp_pow($two, $shift));
|
2831 |
+
|
2832 |
+
break;
|
2833 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
2834 |
+
$temp->value = bcdiv($this->value, bcpow('2', $shift, 0), 0);
|
2835 |
+
|
2836 |
+
break;
|
2837 |
+
default: // could just replace _lshift with this, but then all _lshift() calls would need to be rewritten
|
2838 |
+
// and I don't want to do that...
|
2839 |
+
$temp->value = $this->value;
|
2840 |
+
$temp->_rshift($shift);
|
2841 |
+
}
|
2842 |
+
|
2843 |
+
return $this->_normalize($temp);
|
2844 |
+
}
|
2845 |
+
|
2846 |
+
/**
|
2847 |
+
* Logical Left Shift
|
2848 |
+
*
|
2849 |
+
* Shifts BigInteger's by $shift bits, effectively multiplying by 2**$shift.
|
2850 |
+
*
|
2851 |
+
* @param Integer $shift
|
2852 |
+
* @return Math_BigInteger
|
2853 |
+
* @access public
|
2854 |
+
* @internal The only version that yields any speed increases is the internal version.
|
2855 |
+
*/
|
2856 |
+
function bitwise_leftShift($shift)
|
2857 |
+
{
|
2858 |
+
$temp = new Math_BigInteger();
|
2859 |
+
|
2860 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
2861 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
2862 |
+
static $two;
|
2863 |
+
|
2864 |
+
if (!isset($two)) {
|
2865 |
+
$two = gmp_init('2');
|
2866 |
+
}
|
2867 |
+
|
2868 |
+
$temp->value = gmp_mul($this->value, gmp_pow($two, $shift));
|
2869 |
+
|
2870 |
+
break;
|
2871 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
2872 |
+
$temp->value = bcmul($this->value, bcpow('2', $shift, 0), 0);
|
2873 |
+
|
2874 |
+
break;
|
2875 |
+
default: // could just replace _rshift with this, but then all _lshift() calls would need to be rewritten
|
2876 |
+
// and I don't want to do that...
|
2877 |
+
$temp->value = $this->value;
|
2878 |
+
$temp->_lshift($shift);
|
2879 |
+
}
|
2880 |
+
|
2881 |
+
return $this->_normalize($temp);
|
2882 |
+
}
|
2883 |
+
|
2884 |
+
/**
|
2885 |
+
* Logical Left Rotate
|
2886 |
+
*
|
2887 |
+
* Instead of the top x bits being dropped they're appended to the shifted bit string.
|
2888 |
+
*
|
2889 |
+
* @param Integer $shift
|
2890 |
+
* @return Math_BigInteger
|
2891 |
+
* @access public
|
2892 |
+
*/
|
2893 |
+
function bitwise_leftRotate($shift)
|
2894 |
+
{
|
2895 |
+
$bits = $this->toBytes();
|
2896 |
+
|
2897 |
+
if ($this->precision > 0) {
|
2898 |
+
$precision = $this->precision;
|
2899 |
+
if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
|
2900 |
+
$mask = $this->bitmask->subtract(new Math_BigInteger(1));
|
2901 |
+
$mask = $mask->toBytes();
|
2902 |
+
} else {
|
2903 |
+
$mask = $this->bitmask->toBytes();
|
2904 |
+
}
|
2905 |
+
} else {
|
2906 |
+
$temp = ord($bits[0]);
|
2907 |
+
for ($i = 0; $temp >> $i; ++$i);
|
2908 |
+
$precision = 8 * strlen($bits) - 8 + $i;
|
2909 |
+
$mask = chr((1 << ($precision & 0x7)) - 1) . str_repeat(chr(0xFF), $precision >> 3);
|
2910 |
+
}
|
2911 |
+
|
2912 |
+
if ($shift < 0) {
|
2913 |
+
$shift+= $precision;
|
2914 |
+
}
|
2915 |
+
$shift%= $precision;
|
2916 |
+
|
2917 |
+
if (!$shift) {
|
2918 |
+
return $this->copy();
|
2919 |
+
}
|
2920 |
+
|
2921 |
+
$left = $this->bitwise_leftShift($shift);
|
2922 |
+
$left = $left->bitwise_and(new Math_BigInteger($mask, 256));
|
2923 |
+
$right = $this->bitwise_rightShift($precision - $shift);
|
2924 |
+
$result = MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_BCMATH ? $left->bitwise_or($right) : $left->add($right);
|
2925 |
+
return $this->_normalize($result);
|
2926 |
+
}
|
2927 |
+
|
2928 |
+
/**
|
2929 |
+
* Logical Right Rotate
|
2930 |
+
*
|
2931 |
+
* Instead of the bottom x bits being dropped they're prepended to the shifted bit string.
|
2932 |
+
*
|
2933 |
+
* @param Integer $shift
|
2934 |
+
* @return Math_BigInteger
|
2935 |
+
* @access public
|
2936 |
+
*/
|
2937 |
+
function bitwise_rightRotate($shift)
|
2938 |
+
{
|
2939 |
+
return $this->bitwise_leftRotate(-$shift);
|
2940 |
+
}
|
2941 |
+
|
2942 |
+
/**
|
2943 |
+
* Set random number generator function
|
2944 |
+
*
|
2945 |
+
* $generator should be the name of a random generating function whose first parameter is the minimum
|
2946 |
+
* value and whose second parameter is the maximum value. If this function needs to be seeded, it should
|
2947 |
+
* be seeded prior to calling Math_BigInteger::random() or Math_BigInteger::randomPrime()
|
2948 |
+
*
|
2949 |
+
* If the random generating function is not explicitly set, it'll be assumed to be mt_rand().
|
2950 |
+
*
|
2951 |
+
* @see random()
|
2952 |
+
* @see randomPrime()
|
2953 |
+
* @param optional String $generator
|
2954 |
+
* @access public
|
2955 |
+
*/
|
2956 |
+
function setRandomGenerator($generator)
|
2957 |
+
{
|
2958 |
+
$this->generator = $generator;
|
2959 |
+
}
|
2960 |
+
|
2961 |
+
/**
|
2962 |
+
* Generate a random number
|
2963 |
+
*
|
2964 |
+
* @param optional Integer $min
|
2965 |
+
* @param optional Integer $max
|
2966 |
+
* @return Math_BigInteger
|
2967 |
+
* @access public
|
2968 |
+
*/
|
2969 |
+
function random($min = false, $max = false)
|
2970 |
+
{
|
2971 |
+
if ($min === false) {
|
2972 |
+
$min = new Math_BigInteger(0);
|
2973 |
+
}
|
2974 |
+
|
2975 |
+
if ($max === false) {
|
2976 |
+
$max = new Math_BigInteger(0x7FFFFFFF);
|
2977 |
+
}
|
2978 |
+
|
2979 |
+
$compare = $max->compare($min);
|
2980 |
+
|
2981 |
+
if (!$compare) {
|
2982 |
+
return $this->_normalize($min);
|
2983 |
+
} else if ($compare < 0) {
|
2984 |
+
// if $min is bigger then $max, swap $min and $max
|
2985 |
+
$temp = $max;
|
2986 |
+
$max = $min;
|
2987 |
+
$min = $temp;
|
2988 |
+
}
|
2989 |
+
|
2990 |
+
$generator = $this->generator;
|
2991 |
+
|
2992 |
+
$max = $max->subtract($min);
|
2993 |
+
$max = ltrim($max->toBytes(), chr(0));
|
2994 |
+
$size = strlen($max) - 1;
|
2995 |
+
$random = '';
|
2996 |
+
|
2997 |
+
$bytes = $size & 1;
|
2998 |
+
for ($i = 0; $i < $bytes; ++$i) {
|
2999 |
+
$random.= chr($generator(0, 255));
|
3000 |
+
}
|
3001 |
+
|
3002 |
+
$blocks = $size >> 1;
|
3003 |
+
for ($i = 0; $i < $blocks; ++$i) {
|
3004 |
+
// mt_rand(-2147483648, 0x7FFFFFFF) always produces -2147483648 on some systems
|
3005 |
+
$random.= pack('n', $generator(0, 0xFFFF));
|
3006 |
+
}
|
3007 |
+
|
3008 |
+
$temp = new Math_BigInteger($random, 256);
|
3009 |
+
if ($temp->compare(new Math_BigInteger(substr($max, 1), 256)) > 0) {
|
3010 |
+
$random = chr($generator(0, ord($max[0]) - 1)) . $random;
|
3011 |
+
} else {
|
3012 |
+
$random = chr($generator(0, ord($max[0]) )) . $random;
|
3013 |
+
}
|
3014 |
+
|
3015 |
+
$random = new Math_BigInteger($random, 256);
|
3016 |
+
|
3017 |
+
return $this->_normalize($random->add($min));
|
3018 |
+
}
|
3019 |
+
|
3020 |
+
/**
|
3021 |
+
* Generate a random prime number.
|
3022 |
+
*
|
3023 |
+
* If there's not a prime within the given range, false will be returned. If more than $timeout seconds have elapsed,
|
3024 |
+
* give up and return false.
|
3025 |
+
*
|
3026 |
+
* @param optional Integer $min
|
3027 |
+
* @param optional Integer $max
|
3028 |
+
* @param optional Integer $timeout
|
3029 |
+
* @return Math_BigInteger
|
3030 |
+
* @access public
|
3031 |
+
* @internal See {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=15 HAC 4.44}.
|
3032 |
+
*/
|
3033 |
+
function randomPrime($min = false, $max = false, $timeout = false)
|
3034 |
+
{
|
3035 |
+
$compare = $max->compare($min);
|
3036 |
+
|
3037 |
+
if (!$compare) {
|
3038 |
+
return $min;
|
3039 |
+
} else if ($compare < 0) {
|
3040 |
+
// if $min is bigger then $max, swap $min and $max
|
3041 |
+
$temp = $max;
|
3042 |
+
$max = $min;
|
3043 |
+
$min = $temp;
|
3044 |
+
}
|
3045 |
+
|
3046 |
+
// gmp_nextprime() requires PHP 5 >= 5.2.0 per <http://php.net/gmp-nextprime>.
|
3047 |
+
if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_GMP && function_exists('gmp_nextprime') ) {
|
3048 |
+
// we don't rely on Math_BigInteger::random()'s min / max when gmp_nextprime() is being used since this function
|
3049 |
+
// does its own checks on $max / $min when gmp_nextprime() is used. When gmp_nextprime() is not used, however,
|
3050 |
+
// the same $max / $min checks are not performed.
|
3051 |
+
if ($min === false) {
|
3052 |
+
$min = new Math_BigInteger(0);
|
3053 |
+
}
|
3054 |
+
|
3055 |
+
if ($max === false) {
|
3056 |
+
$max = new Math_BigInteger(0x7FFFFFFF);
|
3057 |
+
}
|
3058 |
+
|
3059 |
+
$x = $this->random($min, $max);
|
3060 |
+
|
3061 |
+
$x->value = gmp_nextprime($x->value);
|
3062 |
+
|
3063 |
+
if ($x->compare($max) <= 0) {
|
3064 |
+
return $x;
|
3065 |
+
}
|
3066 |
+
|
3067 |
+
$x->value = gmp_nextprime($min->value);
|
3068 |
+
|
3069 |
+
if ($x->compare($max) <= 0) {
|
3070 |
+
return $x;
|
3071 |
+
}
|
3072 |
+
|
3073 |
+
return false;
|
3074 |
+
}
|
3075 |
+
|
3076 |
+
static $one, $two;
|
3077 |
+
if (!isset($one)) {
|
3078 |
+
$one = new Math_BigInteger(1);
|
3079 |
+
$two = new Math_BigInteger(2);
|
3080 |
+
}
|
3081 |
+
|
3082 |
+
$start = time();
|
3083 |
+
|
3084 |
+
$x = $this->random($min, $max);
|
3085 |
+
if ($x->equals($two)) {
|
3086 |
+
return $x;
|
3087 |
+
}
|
3088 |
+
|
3089 |
+
$x->_make_odd();
|
3090 |
+
if ($x->compare($max) > 0) {
|
3091 |
+
// if $x > $max then $max is even and if $min == $max then no prime number exists between the specified range
|
3092 |
+
if ($min->equals($max)) {
|
3093 |
+
return false;
|
3094 |
+
}
|
3095 |
+
$x = $min->copy();
|
3096 |
+
$x->_make_odd();
|
3097 |
+
}
|
3098 |
+
|
3099 |
+
$initial_x = $x->copy();
|
3100 |
+
|
3101 |
+
while (true) {
|
3102 |
+
if ($timeout !== false && time() - $start > $timeout) {
|
3103 |
+
return false;
|
3104 |
+
}
|
3105 |
+
|
3106 |
+
if ($x->isPrime()) {
|
3107 |
+
return $x;
|
3108 |
+
}
|
3109 |
+
|
3110 |
+
$x = $x->add($two);
|
3111 |
+
|
3112 |
+
if ($x->compare($max) > 0) {
|
3113 |
+
$x = $min->copy();
|
3114 |
+
if ($x->equals($two)) {
|
3115 |
+
return $x;
|
3116 |
+
}
|
3117 |
+
$x->_make_odd();
|
3118 |
+
}
|
3119 |
+
|
3120 |
+
if ($x->equals($initial_x)) {
|
3121 |
+
return false;
|
3122 |
+
}
|
3123 |
+
}
|
3124 |
+
}
|
3125 |
+
|
3126 |
+
/**
|
3127 |
+
* Make the current number odd
|
3128 |
+
*
|
3129 |
+
* If the current number is odd it'll be unchanged. If it's even, one will be added to it.
|
3130 |
+
*
|
3131 |
+
* @see randomPrime()
|
3132 |
+
* @access private
|
3133 |
+
*/
|
3134 |
+
function _make_odd()
|
3135 |
+
{
|
3136 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
3137 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
3138 |
+
gmp_setbit($this->value, 0);
|
3139 |
+
break;
|
3140 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
3141 |
+
if ($this->value[strlen($this->value) - 1] % 2 == 0) {
|
3142 |
+
$this->value = bcadd($this->value, '1');
|
3143 |
+
}
|
3144 |
+
break;
|
3145 |
+
default:
|
3146 |
+
$this->value[0] |= 1;
|
3147 |
+
}
|
3148 |
+
}
|
3149 |
+
|
3150 |
+
/**
|
3151 |
+
* Checks a numer to see if it's prime
|
3152 |
+
*
|
3153 |
+
* Assuming the $t parameter is not set, this function has an error rate of 2**-80. The main motivation for the
|
3154 |
+
* $t parameter is distributability. Math_BigInteger::randomPrime() can be distributed accross multiple pageloads
|
3155 |
+
* on a website instead of just one.
|
3156 |
+
*
|
3157 |
+
* @param optional Integer $t
|
3158 |
+
* @return Boolean
|
3159 |
+
* @access public
|
3160 |
+
* @internal Uses the
|
3161 |
+
* {@link http://en.wikipedia.org/wiki/Miller%E2%80%93Rabin_primality_test Miller-Rabin primality test}. See
|
3162 |
+
* {@link http://www.cacr.math.uwaterloo.ca/hac/about/chap4.pdf#page=8 HAC 4.24}.
|
3163 |
+
*/
|
3164 |
+
function isPrime($t = false)
|
3165 |
+
{
|
3166 |
+
$length = strlen($this->toBytes());
|
3167 |
+
|
3168 |
+
if (!$t) {
|
3169 |
+
// see HAC 4.49 "Note (controlling the error probability)"
|
3170 |
+
if ($length >= 163) { $t = 2; } // floor(1300 / 8)
|
3171 |
+
else if ($length >= 106) { $t = 3; } // floor( 850 / 8)
|
3172 |
+
else if ($length >= 81 ) { $t = 4; } // floor( 650 / 8)
|
3173 |
+
else if ($length >= 68 ) { $t = 5; } // floor( 550 / 8)
|
3174 |
+
else if ($length >= 56 ) { $t = 6; } // floor( 450 / 8)
|
3175 |
+
else if ($length >= 50 ) { $t = 7; } // floor( 400 / 8)
|
3176 |
+
else if ($length >= 43 ) { $t = 8; } // floor( 350 / 8)
|
3177 |
+
else if ($length >= 37 ) { $t = 9; } // floor( 300 / 8)
|
3178 |
+
else if ($length >= 31 ) { $t = 12; } // floor( 250 / 8)
|
3179 |
+
else if ($length >= 25 ) { $t = 15; } // floor( 200 / 8)
|
3180 |
+
else if ($length >= 18 ) { $t = 18; } // floor( 150 / 8)
|
3181 |
+
else { $t = 27; }
|
3182 |
+
}
|
3183 |
+
|
3184 |
+
// ie. gmp_testbit($this, 0)
|
3185 |
+
// ie. isEven() or !isOdd()
|
3186 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
3187 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
3188 |
+
return gmp_prob_prime($this->value, $t) != 0;
|
3189 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
3190 |
+
if ($this->value === '2') {
|
3191 |
+
return true;
|
3192 |
+
}
|
3193 |
+
if ($this->value[strlen($this->value) - 1] % 2 == 0) {
|
3194 |
+
return false;
|
3195 |
+
}
|
3196 |
+
break;
|
3197 |
+
default:
|
3198 |
+
if ($this->value == array(2)) {
|
3199 |
+
return true;
|
3200 |
+
}
|
3201 |
+
if (~$this->value[0] & 1) {
|
3202 |
+
return false;
|
3203 |
+
}
|
3204 |
+
}
|
3205 |
+
|
3206 |
+
static $primes, $zero, $one, $two;
|
3207 |
+
|
3208 |
+
if (!isset($primes)) {
|
3209 |
+
$primes = array(
|
3210 |
+
3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59,
|
3211 |
+
61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
|
3212 |
+
139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227,
|
3213 |
+
229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283, 293, 307, 311, 313,
|
3214 |
+
317, 331, 337, 347, 349, 353, 359, 367, 373, 379, 383, 389, 397, 401, 409, 419,
|
3215 |
+
421, 431, 433, 439, 443, 449, 457, 461, 463, 467, 479, 487, 491, 499, 503, 509,
|
3216 |
+
521, 523, 541, 547, 557, 563, 569, 571, 577, 587, 593, 599, 601, 607, 613, 617,
|
3217 |
+
619, 631, 641, 643, 647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727,
|
3218 |
+
733, 739, 743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
|
3219 |
+
839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937, 941, 947,
|
3220 |
+
953, 967, 971, 977, 983, 991, 997
|
3221 |
+
);
|
3222 |
+
|
3223 |
+
if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
|
3224 |
+
for ($i = 0; $i < count($primes); ++$i) {
|
3225 |
+
$primes[$i] = new Math_BigInteger($primes[$i]);
|
3226 |
+
}
|
3227 |
+
}
|
3228 |
+
|
3229 |
+
$zero = new Math_BigInteger();
|
3230 |
+
$one = new Math_BigInteger(1);
|
3231 |
+
$two = new Math_BigInteger(2);
|
3232 |
+
}
|
3233 |
+
|
3234 |
+
if ($this->equals($one)) {
|
3235 |
+
return false;
|
3236 |
+
}
|
3237 |
+
|
3238 |
+
// see HAC 4.4.1 "Random search for probable primes"
|
3239 |
+
if ( MATH_BIGINTEGER_MODE != MATH_BIGINTEGER_MODE_INTERNAL ) {
|
3240 |
+
foreach ($primes as $prime) {
|
3241 |
+
list(, $r) = $this->divide($prime);
|
3242 |
+
if ($r->equals($zero)) {
|
3243 |
+
return $this->equals($prime);
|
3244 |
+
}
|
3245 |
+
}
|
3246 |
+
} else {
|
3247 |
+
$value = $this->value;
|
3248 |
+
foreach ($primes as $prime) {
|
3249 |
+
list(, $r) = $this->_divide_digit($value, $prime);
|
3250 |
+
if (!$r) {
|
3251 |
+
return count($value) == 1 && $value[0] == $prime;
|
3252 |
+
}
|
3253 |
+
}
|
3254 |
+
}
|
3255 |
+
|
3256 |
+
$n = $this->copy();
|
3257 |
+
$n_1 = $n->subtract($one);
|
3258 |
+
$n_2 = $n->subtract($two);
|
3259 |
+
|
3260 |
+
$r = $n_1->copy();
|
3261 |
+
$r_value = $r->value;
|
3262 |
+
// ie. $s = gmp_scan1($n, 0) and $r = gmp_div_q($n, gmp_pow(gmp_init('2'), $s));
|
3263 |
+
if ( MATH_BIGINTEGER_MODE == MATH_BIGINTEGER_MODE_BCMATH ) {
|
3264 |
+
$s = 0;
|
3265 |
+
// if $n was 1, $r would be 0 and this would be an infinite loop, hence our $this->equals($one) check earlier
|
3266 |
+
while ($r->value[strlen($r->value) - 1] % 2 == 0) {
|
3267 |
+
$r->value = bcdiv($r->value, '2', 0);
|
3268 |
+
++$s;
|
3269 |
+
}
|
3270 |
+
} else {
|
3271 |
+
for ($i = 0, $r_length = count($r_value); $i < $r_length; ++$i) {
|
3272 |
+
$temp = ~$r_value[$i] & 0xFFFFFF;
|
3273 |
+
for ($j = 1; ($temp >> $j) & 1; ++$j);
|
3274 |
+
if ($j != 25) {
|
3275 |
+
break;
|
3276 |
+
}
|
3277 |
+
}
|
3278 |
+
$s = 26 * $i + $j - 1;
|
3279 |
+
$r->_rshift($s);
|
3280 |
+
}
|
3281 |
+
|
3282 |
+
for ($i = 0; $i < $t; ++$i) {
|
3283 |
+
$a = $this->random($two, $n_2);
|
3284 |
+
$y = $a->modPow($r, $n);
|
3285 |
+
|
3286 |
+
if (!$y->equals($one) && !$y->equals($n_1)) {
|
3287 |
+
for ($j = 1; $j < $s && !$y->equals($n_1); ++$j) {
|
3288 |
+
$y = $y->modPow($two, $n);
|
3289 |
+
if ($y->equals($one)) {
|
3290 |
+
return false;
|
3291 |
+
}
|
3292 |
+
}
|
3293 |
+
|
3294 |
+
if (!$y->equals($n_1)) {
|
3295 |
+
return false;
|
3296 |
+
}
|
3297 |
+
}
|
3298 |
+
}
|
3299 |
+
return true;
|
3300 |
+
}
|
3301 |
+
|
3302 |
+
/**
|
3303 |
+
* Logical Left Shift
|
3304 |
+
*
|
3305 |
+
* Shifts BigInteger's by $shift bits.
|
3306 |
+
*
|
3307 |
+
* @param Integer $shift
|
3308 |
+
* @access private
|
3309 |
+
*/
|
3310 |
+
function _lshift($shift)
|
3311 |
+
{
|
3312 |
+
if ( $shift == 0 ) {
|
3313 |
+
return;
|
3314 |
+
}
|
3315 |
+
|
3316 |
+
$num_digits = (int) ($shift / 26);
|
3317 |
+
$shift %= 26;
|
3318 |
+
$shift = 1 << $shift;
|
3319 |
+
|
3320 |
+
$carry = 0;
|
3321 |
+
|
3322 |
+
for ($i = 0; $i < count($this->value); ++$i) {
|
3323 |
+
$temp = $this->value[$i] * $shift + $carry;
|
3324 |
+
$carry = (int) ($temp / 0x4000000);
|
3325 |
+
$this->value[$i] = (int) ($temp - $carry * 0x4000000);
|
3326 |
+
}
|
3327 |
+
|
3328 |
+
if ( $carry ) {
|
3329 |
+
$this->value[] = $carry;
|
3330 |
+
}
|
3331 |
+
|
3332 |
+
while ($num_digits--) {
|
3333 |
+
array_unshift($this->value, 0);
|
3334 |
+
}
|
3335 |
+
}
|
3336 |
+
|
3337 |
+
/**
|
3338 |
+
* Logical Right Shift
|
3339 |
+
*
|
3340 |
+
* Shifts BigInteger's by $shift bits.
|
3341 |
+
*
|
3342 |
+
* @param Integer $shift
|
3343 |
+
* @access private
|
3344 |
+
*/
|
3345 |
+
function _rshift($shift)
|
3346 |
+
{
|
3347 |
+
if ($shift == 0) {
|
3348 |
+
return;
|
3349 |
+
}
|
3350 |
+
|
3351 |
+
$num_digits = (int) ($shift / 26);
|
3352 |
+
$shift %= 26;
|
3353 |
+
$carry_shift = 26 - $shift;
|
3354 |
+
$carry_mask = (1 << $shift) - 1;
|
3355 |
+
|
3356 |
+
if ( $num_digits ) {
|
3357 |
+
$this->value = array_slice($this->value, $num_digits);
|
3358 |
+
}
|
3359 |
+
|
3360 |
+
$carry = 0;
|
3361 |
+
|
3362 |
+
for ($i = count($this->value) - 1; $i >= 0; --$i) {
|
3363 |
+
$temp = $this->value[$i] >> $shift | $carry;
|
3364 |
+
$carry = ($this->value[$i] & $carry_mask) << $carry_shift;
|
3365 |
+
$this->value[$i] = $temp;
|
3366 |
+
}
|
3367 |
+
|
3368 |
+
$this->value = $this->_trim($this->value);
|
3369 |
+
}
|
3370 |
+
|
3371 |
+
/**
|
3372 |
+
* Normalize
|
3373 |
+
*
|
3374 |
+
* Removes leading zeros and truncates (if necessary) to maintain the appropriate precision
|
3375 |
+
*
|
3376 |
+
* @param Math_BigInteger
|
3377 |
+
* @return Math_BigInteger
|
3378 |
+
* @see _trim()
|
3379 |
+
* @access private
|
3380 |
+
*/
|
3381 |
+
function _normalize($result)
|
3382 |
+
{
|
3383 |
+
$result->precision = $this->precision;
|
3384 |
+
$result->bitmask = $this->bitmask;
|
3385 |
+
|
3386 |
+
switch ( MATH_BIGINTEGER_MODE ) {
|
3387 |
+
case MATH_BIGINTEGER_MODE_GMP:
|
3388 |
+
if (!empty($result->bitmask->value)) {
|
3389 |
+
$result->value = gmp_and($result->value, $result->bitmask->value);
|
3390 |
+
}
|
3391 |
+
|
3392 |
+
return $result;
|
3393 |
+
case MATH_BIGINTEGER_MODE_BCMATH:
|
3394 |
+
if (!empty($result->bitmask->value)) {
|
3395 |
+
$result->value = bcmod($result->value, $result->bitmask->value);
|
3396 |
+
}
|
3397 |
+
|
3398 |
+
return $result;
|
3399 |
+
}
|
3400 |
+
|
3401 |
+
$value = &$result->value;
|
3402 |
+
|
3403 |
+
if ( !count($value) ) {
|
3404 |
+
return $result;
|
3405 |
+
}
|
3406 |
+
|
3407 |
+
$value = $this->_trim($value);
|
3408 |
+
|
3409 |
+
if (!empty($result->bitmask->value)) {
|
3410 |
+
$length = min(count($value), count($this->bitmask->value));
|
3411 |
+
$value = array_slice($value, 0, $length);
|
3412 |
+
|
3413 |
+
for ($i = 0; $i < $length; ++$i) {
|
3414 |
+
$value[$i] = $value[$i] & $this->bitmask->value[$i];
|
3415 |
+
}
|
3416 |
+
}
|
3417 |
+
|
3418 |
+
return $result;
|
3419 |
+
}
|
3420 |
+
|
3421 |
+
/**
|
3422 |
+
* Trim
|
3423 |
+
*
|
3424 |
+
* Removes leading zeros
|
3425 |
+
*
|
3426 |
+
* @return Math_BigInteger
|
3427 |
+
* @access private
|
3428 |
+
*/
|
3429 |
+
function _trim($value)
|
3430 |
+
{
|
3431 |
+
for ($i = count($value) - 1; $i >= 0; --$i) {
|
3432 |
+
if ( $value[$i] ) {
|
3433 |
+
break;
|
3434 |
+
}
|
3435 |
+
unset($value[$i]);
|
3436 |
+
}
|
3437 |
+
|
3438 |
+
return $value;
|
3439 |
+
}
|
3440 |
+
|
3441 |
+
/**
|
3442 |
+
* Array Repeat
|
3443 |
+
*
|
3444 |
+
* @param $input Array
|
3445 |
+
* @param $multiplier mixed
|
3446 |
+
* @return Array
|
3447 |
+
* @access private
|
3448 |
+
*/
|
3449 |
+
function _array_repeat($input, $multiplier)
|
3450 |
+
{
|
3451 |
+
return ($multiplier) ? array_fill(0, $multiplier, $input) : array();
|
3452 |
+
}
|
3453 |
+
|
3454 |
+
/**
|
3455 |
+
* Logical Left Shift
|
3456 |
+
*
|
3457 |
+
* Shifts binary strings $shift bits, essentially multiplying by 2**$shift.
|
3458 |
+
*
|
3459 |
+
* @param $x String
|
3460 |
+
* @param $shift Integer
|
3461 |
+
* @return String
|
3462 |
+
* @access private
|
3463 |
+
*/
|
3464 |
+
function _base256_lshift(&$x, $shift)
|
3465 |
+
{
|
3466 |
+
if ($shift == 0) {
|
3467 |
+
return;
|
3468 |
+
}
|
3469 |
+
|
3470 |
+
$num_bytes = $shift >> 3; // eg. floor($shift/8)
|
3471 |
+
$shift &= 7; // eg. $shift % 8
|
3472 |
+
|
3473 |
+
$carry = 0;
|
3474 |
+
for ($i = strlen($x) - 1; $i >= 0; --$i) {
|
3475 |
+
$temp = ord($x[$i]) << $shift | $carry;
|
3476 |
+
$x[$i] = chr($temp);
|
3477 |
+
$carry = $temp >> 8;
|
3478 |
+
}
|
3479 |
+
$carry = ($carry != 0) ? chr($carry) : '';
|
3480 |
+
$x = $carry . $x . str_repeat(chr(0), $num_bytes);
|
3481 |
+
}
|
3482 |
+
|
3483 |
+
/**
|
3484 |
+
* Logical Right Shift
|
3485 |
+
*
|
3486 |
+
* Shifts binary strings $shift bits, essentially dividing by 2**$shift and returning the remainder.
|
3487 |
+
*
|
3488 |
+
* @param $x String
|
3489 |
+
* @param $shift Integer
|
3490 |
+
* @return String
|
3491 |
+
* @access private
|
3492 |
+
*/
|
3493 |
+
function _base256_rshift(&$x, $shift)
|
3494 |
+
{
|
3495 |
+
if ($shift == 0) {
|
3496 |
+
$x = ltrim($x, chr(0));
|
3497 |
+
return '';
|
3498 |
+
}
|
3499 |
+
|
3500 |
+
$num_bytes = $shift >> 3; // eg. floor($shift/8)
|
3501 |
+
$shift &= 7; // eg. $shift % 8
|
3502 |
+
|
3503 |
+
$remainder = '';
|
3504 |
+
if ($num_bytes) {
|
3505 |
+
$start = $num_bytes > strlen($x) ? -strlen($x) : -$num_bytes;
|
3506 |
+
$remainder = substr($x, $start);
|
3507 |
+
$x = substr($x, 0, -$num_bytes);
|
3508 |
+
}
|
3509 |
+
|
3510 |
+
$carry = 0;
|
3511 |
+
$carry_shift = 8 - $shift;
|
3512 |
+
for ($i = 0; $i < strlen($x); ++$i) {
|
3513 |
+
$temp = (ord($x[$i]) >> $shift) | $carry;
|
3514 |
+
$carry = (ord($x[$i]) << $carry_shift) & 0xFF;
|
3515 |
+
$x[$i] = chr($temp);
|
3516 |
+
}
|
3517 |
+
$x = ltrim($x, chr(0));
|
3518 |
+
|
3519 |
+
$remainder = chr($carry >> $carry_shift) . $remainder;
|
3520 |
+
|
3521 |
+
return ltrim($remainder, chr(0));
|
3522 |
+
}
|
3523 |
+
|
3524 |
+
// one quirk about how the following functions are implemented is that PHP defines N to be an unsigned long
|
3525 |
+
// at 32-bits, while java's longs are 64-bits.
|
3526 |
+
|
3527 |
+
/**
|
3528 |
+
* Converts 32-bit integers to bytes.
|
3529 |
+
*
|
3530 |
+
* @param Integer $x
|
3531 |
+
* @return String
|
3532 |
+
* @access private
|
3533 |
+
*/
|
3534 |
+
function _int2bytes($x)
|
3535 |
+
{
|
3536 |
+
return ltrim(pack('N', $x), chr(0));
|
3537 |
+
}
|
3538 |
+
|
3539 |
+
/**
|
3540 |
+
* Converts bytes to 32-bit integers
|
3541 |
+
*
|
3542 |
+
* @param String $x
|
3543 |
+
* @return Integer
|
3544 |
+
* @access private
|
3545 |
+
*/
|
3546 |
+
function _bytes2int($x)
|
3547 |
+
{
|
3548 |
+
$temp = unpack('Nint', str_pad($x, 4, chr(0), STR_PAD_LEFT));
|
3549 |
+
return $temp['int'];
|
3550 |
+
}
|
3551 |
+
}
|
classes/phpseclib/Net/SFTP.php
ADDED
@@ -0,0 +1,1609 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of SFTP.
|
6 |
+
*
|
7 |
+
* PHP versions 4 and 5
|
8 |
+
*
|
9 |
+
* Currently only supports SFTPv3, which, according to wikipedia.org, "is the most widely used version,
|
10 |
+
* implemented by the popular OpenSSH SFTP server". If you want SFTPv4/5/6 support, provide me with access
|
11 |
+
* to an SFTPv4/5/6 server.
|
12 |
+
*
|
13 |
+
* The API for this library is modeled after the API from PHP's {@link http://php.net/book.ftp FTP extension}.
|
14 |
+
*
|
15 |
+
* Here's a short example of how to use this library:
|
16 |
+
* <code>
|
17 |
+
* <?php
|
18 |
+
* include('Net/SFTP.php');
|
19 |
+
*
|
20 |
+
* $sftp = new Net_SFTP('www.domain.tld');
|
21 |
+
* if (!$sftp->login('username', 'password')) {
|
22 |
+
* exit('Login Failed');
|
23 |
+
* }
|
24 |
+
*
|
25 |
+
* echo $sftp->pwd() . "\r\n";
|
26 |
+
* $sftp->put('filename.ext', 'hello, world!');
|
27 |
+
* print_r($sftp->nlist());
|
28 |
+
* ?>
|
29 |
+
* </code>
|
30 |
+
*
|
31 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
32 |
+
* of this software and associated documentation files (the "Software"), to deal
|
33 |
+
* in the Software without restriction, including without limitation the rights
|
34 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
35 |
+
* copies of the Software, and to permit persons to whom the Software is
|
36 |
+
* furnished to do so, subject to the following conditions:
|
37 |
+
*
|
38 |
+
* The above copyright notice and this permission notice shall be included in
|
39 |
+
* all copies or substantial portions of the Software.
|
40 |
+
*
|
41 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
42 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
43 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
44 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
45 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
46 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
47 |
+
* THE SOFTWARE.
|
48 |
+
*
|
49 |
+
* @category Net
|
50 |
+
* @package Net_SFTP
|
51 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
52 |
+
* @copyright MMIX Jim Wigginton
|
53 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
54 |
+
* @link http://phpseclib.sourceforge.net
|
55 |
+
*/
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Include Net_SSH2
|
59 |
+
*/
|
60 |
+
require_once('Net/SSH2.php');
|
61 |
+
|
62 |
+
/**#@+
|
63 |
+
* @access public
|
64 |
+
* @see Net_SFTP::getLog()
|
65 |
+
*/
|
66 |
+
/**
|
67 |
+
* Returns the message numbers
|
68 |
+
*/
|
69 |
+
define('NET_SFTP_LOG_SIMPLE', NET_SSH2_LOG_SIMPLE);
|
70 |
+
/**
|
71 |
+
* Returns the message content
|
72 |
+
*/
|
73 |
+
define('NET_SFTP_LOG_COMPLEX', NET_SSH2_LOG_COMPLEX);
|
74 |
+
/**#@-*/
|
75 |
+
|
76 |
+
/**
|
77 |
+
* SFTP channel constant
|
78 |
+
*
|
79 |
+
* Net_SSH2::exec() uses 0 and Net_SSH2::read() / Net_SSH2::write() use 1.
|
80 |
+
*
|
81 |
+
* @see Net_SSH2::_send_channel_packet()
|
82 |
+
* @see Net_SSH2::_get_channel_packet()
|
83 |
+
* @access private
|
84 |
+
*/
|
85 |
+
define('NET_SFTP_CHANNEL', 2);
|
86 |
+
|
87 |
+
/**#@+
|
88 |
+
* @access public
|
89 |
+
* @see Net_SFTP::put()
|
90 |
+
*/
|
91 |
+
/**
|
92 |
+
* Reads data from a local file.
|
93 |
+
*/
|
94 |
+
define('NET_SFTP_LOCAL_FILE', 1);
|
95 |
+
/**
|
96 |
+
* Reads data from a string.
|
97 |
+
*/
|
98 |
+
define('NET_SFTP_STRING', 2);
|
99 |
+
/**#@-*/
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Pure-PHP implementations of SFTP.
|
103 |
+
*
|
104 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
105 |
+
* @version 0.1.0
|
106 |
+
* @access public
|
107 |
+
* @package Net_SFTP
|
108 |
+
*/
|
109 |
+
class Net_SFTP extends Net_SSH2 {
|
110 |
+
/**
|
111 |
+
* Packet Types
|
112 |
+
*
|
113 |
+
* @see Net_SFTP::Net_SFTP()
|
114 |
+
* @var Array
|
115 |
+
* @access private
|
116 |
+
*/
|
117 |
+
var $packet_types = array();
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Status Codes
|
121 |
+
*
|
122 |
+
* @see Net_SFTP::Net_SFTP()
|
123 |
+
* @var Array
|
124 |
+
* @access private
|
125 |
+
*/
|
126 |
+
var $status_codes = array();
|
127 |
+
|
128 |
+
/**
|
129 |
+
* The Request ID
|
130 |
+
*
|
131 |
+
* The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
|
132 |
+
* concurrent actions, so it's somewhat academic, here.
|
133 |
+
*
|
134 |
+
* @var Integer
|
135 |
+
* @see Net_SFTP::_send_sftp_packet()
|
136 |
+
* @access private
|
137 |
+
*/
|
138 |
+
var $request_id = false;
|
139 |
+
|
140 |
+
/**
|
141 |
+
* The Packet Type
|
142 |
+
*
|
143 |
+
* The request ID exists in the off chance that a packet is sent out-of-order. Of course, this library doesn't support
|
144 |
+
* concurrent actions, so it's somewhat academic, here.
|
145 |
+
*
|
146 |
+
* @var Integer
|
147 |
+
* @see Net_SFTP::_get_sftp_packet()
|
148 |
+
* @access private
|
149 |
+
*/
|
150 |
+
var $packet_type = -1;
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Packet Buffer
|
154 |
+
*
|
155 |
+
* @var String
|
156 |
+
* @see Net_SFTP::_get_sftp_packet()
|
157 |
+
* @access private
|
158 |
+
*/
|
159 |
+
var $packet_buffer = '';
|
160 |
+
|
161 |
+
/**
|
162 |
+
* Extensions supported by the server
|
163 |
+
*
|
164 |
+
* @var Array
|
165 |
+
* @see Net_SFTP::_initChannel()
|
166 |
+
* @access private
|
167 |
+
*/
|
168 |
+
var $extensions = array();
|
169 |
+
|
170 |
+
/**
|
171 |
+
* Server SFTP version
|
172 |
+
*
|
173 |
+
* @var Integer
|
174 |
+
* @see Net_SFTP::_initChannel()
|
175 |
+
* @access private
|
176 |
+
*/
|
177 |
+
var $version;
|
178 |
+
|
179 |
+
/**
|
180 |
+
* Current working directory
|
181 |
+
*
|
182 |
+
* @var String
|
183 |
+
* @see Net_SFTP::_realpath()
|
184 |
+
* @see Net_SFTP::chdir()
|
185 |
+
* @access private
|
186 |
+
*/
|
187 |
+
var $pwd = false;
|
188 |
+
|
189 |
+
/**
|
190 |
+
* Packet Type Log
|
191 |
+
*
|
192 |
+
* @see Net_SFTP::getLog()
|
193 |
+
* @var Array
|
194 |
+
* @access private
|
195 |
+
*/
|
196 |
+
var $packet_type_log = array();
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Packet Log
|
200 |
+
*
|
201 |
+
* @see Net_SFTP::getLog()
|
202 |
+
* @var Array
|
203 |
+
* @access private
|
204 |
+
*/
|
205 |
+
var $packet_log = array();
|
206 |
+
|
207 |
+
/**
|
208 |
+
* Error information
|
209 |
+
*
|
210 |
+
* @see Net_SFTP::getSFTPErrors()
|
211 |
+
* @see Net_SFTP::getLastSFTPError()
|
212 |
+
* @var String
|
213 |
+
* @access private
|
214 |
+
*/
|
215 |
+
var $sftp_errors = array();
|
216 |
+
|
217 |
+
/**
|
218 |
+
* File Type
|
219 |
+
*
|
220 |
+
* @see Net_SFTP::_parseLongname()
|
221 |
+
* @var Integer
|
222 |
+
* @access private
|
223 |
+
*/
|
224 |
+
var $fileType = 0;
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Default Constructor.
|
228 |
+
*
|
229 |
+
* Connects to an SFTP server
|
230 |
+
*
|
231 |
+
* @param String $host
|
232 |
+
* @param optional Integer $port
|
233 |
+
* @param optional Integer $timeout
|
234 |
+
* @return Net_SFTP
|
235 |
+
* @access public
|
236 |
+
*/
|
237 |
+
function Net_SFTP($host, $port = 22, $timeout = 10)
|
238 |
+
{
|
239 |
+
parent::Net_SSH2($host, $port, $timeout);
|
240 |
+
$this->packet_types = array(
|
241 |
+
1 => 'NET_SFTP_INIT',
|
242 |
+
2 => 'NET_SFTP_VERSION',
|
243 |
+
/* the format of SSH_FXP_OPEN changed between SFTPv4 and SFTPv5+:
|
244 |
+
SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.1
|
245 |
+
pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3 */
|
246 |
+
3 => 'NET_SFTP_OPEN',
|
247 |
+
4 => 'NET_SFTP_CLOSE',
|
248 |
+
5 => 'NET_SFTP_READ',
|
249 |
+
6 => 'NET_SFTP_WRITE',
|
250 |
+
7 => 'NET_SFTP_LSTAT',
|
251 |
+
9 => 'NET_SFTP_SETSTAT',
|
252 |
+
11 => 'NET_SFTP_OPENDIR',
|
253 |
+
12 => 'NET_SFTP_READDIR',
|
254 |
+
13 => 'NET_SFTP_REMOVE',
|
255 |
+
14 => 'NET_SFTP_MKDIR',
|
256 |
+
15 => 'NET_SFTP_RMDIR',
|
257 |
+
16 => 'NET_SFTP_REALPATH',
|
258 |
+
17 => 'NET_SFTP_STAT',
|
259 |
+
/* the format of SSH_FXP_RENAME changed between SFTPv4 and SFTPv5+:
|
260 |
+
SFTPv5+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
|
261 |
+
pre-SFTPv5 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.5 */
|
262 |
+
18 => 'NET_SFTP_RENAME',
|
263 |
+
|
264 |
+
101=> 'NET_SFTP_STATUS',
|
265 |
+
102=> 'NET_SFTP_HANDLE',
|
266 |
+
/* the format of SSH_FXP_NAME changed between SFTPv3 and SFTPv4+:
|
267 |
+
SFTPv4+: http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.4
|
268 |
+
pre-SFTPv4 : http://tools.ietf.org/html/draft-ietf-secsh-filexfer-02#section-7 */
|
269 |
+
103=> 'NET_SFTP_DATA',
|
270 |
+
104=> 'NET_SFTP_NAME',
|
271 |
+
105=> 'NET_SFTP_ATTRS',
|
272 |
+
|
273 |
+
200=> 'NET_SFTP_EXTENDED'
|
274 |
+
);
|
275 |
+
$this->status_codes = array(
|
276 |
+
0 => 'NET_SFTP_STATUS_OK',
|
277 |
+
1 => 'NET_SFTP_STATUS_EOF',
|
278 |
+
2 => 'NET_SFTP_STATUS_NO_SUCH_FILE',
|
279 |
+
3 => 'NET_SFTP_STATUS_PERMISSION_DENIED',
|
280 |
+
4 => 'NET_SFTP_STATUS_FAILURE',
|
281 |
+
5 => 'NET_SFTP_STATUS_BAD_MESSAGE',
|
282 |
+
6 => 'NET_SFTP_STATUS_NO_CONNECTION',
|
283 |
+
7 => 'NET_SFTP_STATUS_CONNECTION_LOST',
|
284 |
+
8 => 'NET_SFTP_STATUS_OP_UNSUPPORTED'
|
285 |
+
);
|
286 |
+
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-7.1
|
287 |
+
// the order, in this case, matters quite a lot - see Net_SFTP::_parseAttributes() to understand why
|
288 |
+
$this->attributes = array(
|
289 |
+
0x00000001 => 'NET_SFTP_ATTR_SIZE',
|
290 |
+
0x00000002 => 'NET_SFTP_ATTR_UIDGID', // defined in SFTPv3, removed in SFTPv4+
|
291 |
+
0x00000004 => 'NET_SFTP_ATTR_PERMISSIONS',
|
292 |
+
0x00000008 => 'NET_SFTP_ATTR_ACCESSTIME',
|
293 |
+
// 0x80000000 will yield a floating point on 32-bit systems and converting floating points to integers
|
294 |
+
// yields inconsistent behavior depending on how php is compiled. so we left shift -1 (which, in
|
295 |
+
// two's compliment, consists of all 1 bits) by 31. on 64-bit systems this'll yield 0xFFFFFFFF80000000.
|
296 |
+
// that's not a problem, however, and 'anded' and a 32-bit number, as all the leading 1 bits are ignored.
|
297 |
+
-1 << 31 => 'NET_SFTP_ATTR_EXTENDED'
|
298 |
+
);
|
299 |
+
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-6.3
|
300 |
+
// the flag definitions change somewhat in SFTPv5+. if SFTPv5+ support is added to this library, maybe name
|
301 |
+
// the array for that $this->open5_flags and similarily alter the constant names.
|
302 |
+
$this->open_flags = array(
|
303 |
+
0x00000001 => 'NET_SFTP_OPEN_READ',
|
304 |
+
0x00000002 => 'NET_SFTP_OPEN_WRITE',
|
305 |
+
0x00000008 => 'NET_SFTP_OPEN_CREATE',
|
306 |
+
0x00000010 => 'NET_SFTP_OPEN_TRUNCATE'
|
307 |
+
);
|
308 |
+
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2
|
309 |
+
// see Net_SFTP::_parseLongname() for an explanation
|
310 |
+
$this->file_types = array(
|
311 |
+
1 => 'NET_SFTP_TYPE_REGULAR',
|
312 |
+
2 => 'NET_SFTP_TYPE_DIRECTORY',
|
313 |
+
3 => 'NET_SFTP_TYPE_SYMLINK',
|
314 |
+
4 => 'NET_SFTP_TYPE_SPECIAL'
|
315 |
+
);
|
316 |
+
$this->_define_array(
|
317 |
+
$this->packet_types,
|
318 |
+
$this->status_codes,
|
319 |
+
$this->attributes,
|
320 |
+
$this->open_flags,
|
321 |
+
$this->file_types
|
322 |
+
);
|
323 |
+
}
|
324 |
+
|
325 |
+
/**
|
326 |
+
* Login
|
327 |
+
*
|
328 |
+
* @param String $username
|
329 |
+
* @param optional String $password
|
330 |
+
* @return Boolean
|
331 |
+
* @access public
|
332 |
+
*/
|
333 |
+
function login($username, $password = '')
|
334 |
+
{
|
335 |
+
if (!parent::login($username, $password)) {
|
336 |
+
return false;
|
337 |
+
}
|
338 |
+
|
339 |
+
$this->window_size_client_to_server[NET_SFTP_CHANNEL] = $this->window_size;
|
340 |
+
|
341 |
+
$packet = pack('CNa*N3',
|
342 |
+
NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SFTP_CHANNEL, $this->window_size, 0x4000);
|
343 |
+
|
344 |
+
if (!$this->_send_binary_packet($packet)) {
|
345 |
+
return false;
|
346 |
+
}
|
347 |
+
|
348 |
+
$this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_OPEN;
|
349 |
+
|
350 |
+
$response = $this->_get_channel_packet(NET_SFTP_CHANNEL);
|
351 |
+
if ($response === false) {
|
352 |
+
return false;
|
353 |
+
}
|
354 |
+
|
355 |
+
$packet = pack('CNNa*CNa*',
|
356 |
+
NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SFTP_CHANNEL], strlen('subsystem'), 'subsystem', 1, strlen('sftp'), 'sftp');
|
357 |
+
if (!$this->_send_binary_packet($packet)) {
|
358 |
+
return false;
|
359 |
+
}
|
360 |
+
|
361 |
+
$this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_REQUEST;
|
362 |
+
|
363 |
+
$response = $this->_get_channel_packet(NET_SFTP_CHANNEL);
|
364 |
+
if ($response === false) {
|
365 |
+
return false;
|
366 |
+
}
|
367 |
+
|
368 |
+
$this->channel_status[NET_SFTP_CHANNEL] = NET_SSH2_MSG_CHANNEL_DATA;
|
369 |
+
|
370 |
+
if (!$this->_send_sftp_packet(NET_SFTP_INIT, "\0\0\0\3")) {
|
371 |
+
return false;
|
372 |
+
}
|
373 |
+
|
374 |
+
$response = $this->_get_sftp_packet();
|
375 |
+
if ($this->packet_type != NET_SFTP_VERSION) {
|
376 |
+
user_error('Expected SSH_FXP_VERSION', E_USER_NOTICE);
|
377 |
+
return false;
|
378 |
+
}
|
379 |
+
|
380 |
+
extract(unpack('Nversion', $this->_string_shift($response, 4)));
|
381 |
+
$this->version = $version;
|
382 |
+
while (!empty($response)) {
|
383 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
384 |
+
$key = $this->_string_shift($response, $length);
|
385 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
386 |
+
$value = $this->_string_shift($response, $length);
|
387 |
+
$this->extensions[$key] = $value;
|
388 |
+
}
|
389 |
+
|
390 |
+
/*
|
391 |
+
SFTPv4+ defines a 'newline' extension. SFTPv3 seems to have unofficial support for it via 'newline@vandyke.com',
|
392 |
+
however, I'm not sure what 'newline@vandyke.com' is supposed to do (the fact that it's unofficial means that it's
|
393 |
+
not in the official SFTPv3 specs) and 'newline@vandyke.com' / 'newline' are likely not drop-in substitutes for
|
394 |
+
one another due to the fact that 'newline' comes with a SSH_FXF_TEXT bitmask whereas it seems unlikely that
|
395 |
+
'newline@vandyke.com' would.
|
396 |
+
*/
|
397 |
+
/*
|
398 |
+
if (isset($this->extensions['newline@vandyke.com'])) {
|
399 |
+
$this->extensions['newline'] = $this->extensions['newline@vandyke.com'];
|
400 |
+
unset($this->extensions['newline@vandyke.com']);
|
401 |
+
}
|
402 |
+
*/
|
403 |
+
|
404 |
+
$this->request_id = 1;
|
405 |
+
|
406 |
+
/*
|
407 |
+
A Note on SFTPv4/5/6 support:
|
408 |
+
<http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.1> states the following:
|
409 |
+
|
410 |
+
"If the client wishes to interoperate with servers that support noncontiguous version
|
411 |
+
numbers it SHOULD send '3'"
|
412 |
+
|
413 |
+
Given that the server only sends its version number after the client has already done so, the above
|
414 |
+
seems to be suggesting that v3 should be the default version. This makes sense given that v3 is the
|
415 |
+
most popular.
|
416 |
+
|
417 |
+
<http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-5.5> states the following;
|
418 |
+
|
419 |
+
"If the server did not send the "versions" extension, or the version-from-list was not included, the
|
420 |
+
server MAY send a status response describing the failure, but MUST then close the channel without
|
421 |
+
processing any further requests."
|
422 |
+
|
423 |
+
So what do you do if you have a client whose initial SSH_FXP_INIT packet says it implements v3 and
|
424 |
+
a server whose initial SSH_FXP_VERSION reply says it implements v4 and only v4? If it only implements
|
425 |
+
v4, the "versions" extension is likely not going to have been sent so version re-negotiation as discussed
|
426 |
+
in draft-ietf-secsh-filexfer-13 would be quite impossible. As such, what Net_SFTP would do is close the
|
427 |
+
channel and reopen it with a new and updated SSH_FXP_INIT packet.
|
428 |
+
*/
|
429 |
+
if ($this->version != 3) {
|
430 |
+
return false;
|
431 |
+
}
|
432 |
+
|
433 |
+
$this->pwd = $this->_realpath('.');
|
434 |
+
|
435 |
+
return true;
|
436 |
+
}
|
437 |
+
|
438 |
+
/**
|
439 |
+
* Returns the current directory name
|
440 |
+
*
|
441 |
+
* @return Mixed
|
442 |
+
* @access public
|
443 |
+
*/
|
444 |
+
function pwd()
|
445 |
+
{
|
446 |
+
return $this->pwd;
|
447 |
+
}
|
448 |
+
|
449 |
+
/**
|
450 |
+
* Canonicalize the Server-Side Path Name
|
451 |
+
*
|
452 |
+
* SFTP doesn't provide a mechanism by which the current working directory can be changed, so we'll emulate it. Returns
|
453 |
+
* the absolute (canonicalized) path. If $mode is set to NET_SFTP_CONFIRM_DIR (as opposed to NET_SFTP_CONFIRM_NONE,
|
454 |
+
* which is what it is set to by default), false is returned if $dir is not a valid directory.
|
455 |
+
*
|
456 |
+
* @see Net_SFTP::chdir()
|
457 |
+
* @param String $dir
|
458 |
+
* @param optional Integer $mode
|
459 |
+
* @return Mixed
|
460 |
+
* @access private
|
461 |
+
*/
|
462 |
+
function _realpath($dir)
|
463 |
+
{
|
464 |
+
/*
|
465 |
+
"This protocol represents file names as strings. File names are
|
466 |
+
assumed to use the slash ('/') character as a directory separator.
|
467 |
+
|
468 |
+
File names starting with a slash are "absolute", and are relative to
|
469 |
+
the root of the file system. Names starting with any other character
|
470 |
+
are relative to the user's default directory (home directory). Note
|
471 |
+
that identifying the user is assumed to take place outside of this
|
472 |
+
protocol."
|
473 |
+
|
474 |
+
-- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-6
|
475 |
+
*/
|
476 |
+
$file = '';
|
477 |
+
if ($this->pwd !== false) {
|
478 |
+
// if the SFTP server returned the canonicalized path even for non-existant files this wouldn't be necessary
|
479 |
+
// on OpenSSH it isn't necessary but on other SFTP servers it is. that and since the specs say nothing on
|
480 |
+
// the subject, we'll go ahead and work around it with the following.
|
481 |
+
if ($dir[strlen($dir) - 1] != '/') {
|
482 |
+
$file = basename($dir);
|
483 |
+
$dir = dirname($dir);
|
484 |
+
}
|
485 |
+
|
486 |
+
if ($dir == '.' || $dir == $this->pwd) {
|
487 |
+
return $this->pwd . $file;
|
488 |
+
}
|
489 |
+
|
490 |
+
if ($dir[0] != '/') {
|
491 |
+
$dir = $this->pwd . '/' . $dir;
|
492 |
+
}
|
493 |
+
// on the surface it seems like maybe resolving a path beginning with / is unnecessary, but such paths
|
494 |
+
// can contain .'s and ..'s just like any other. we could parse those out as appropriate or we can let
|
495 |
+
// the server do it. we'll do the latter.
|
496 |
+
}
|
497 |
+
|
498 |
+
/*
|
499 |
+
that SSH_FXP_REALPATH returns SSH_FXP_NAME does not necessarily mean that anything actually exists at the
|
500 |
+
specified path. generally speaking, no attributes are returned with this particular SSH_FXP_NAME packet
|
501 |
+
regardless of whether or not a file actually exists. and in SFTPv3, the longname field and the filename
|
502 |
+
field match for this particular SSH_FXP_NAME packet. for other SSH_FXP_NAME packets, this will likely
|
503 |
+
not be the case, but for this one, it is.
|
504 |
+
*/
|
505 |
+
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.9
|
506 |
+
if (!$this->_send_sftp_packet(NET_SFTP_REALPATH, pack('Na*', strlen($dir), $dir))) {
|
507 |
+
return false;
|
508 |
+
}
|
509 |
+
|
510 |
+
$response = $this->_get_sftp_packet();
|
511 |
+
switch ($this->packet_type) {
|
512 |
+
case NET_SFTP_NAME:
|
513 |
+
// although SSH_FXP_NAME is implemented differently in SFTPv3 than it is in SFTPv4+, the following
|
514 |
+
// should work on all SFTP versions since the only part of the SSH_FXP_NAME packet the following looks
|
515 |
+
// at is the first part and that part is defined the same in SFTP versions 3 through 6.
|
516 |
+
$this->_string_shift($response, 4); // skip over the count - it should be 1, anyway
|
517 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
518 |
+
$realpath = $this->_string_shift($response, $length);
|
519 |
+
// the following is SFTPv3 only code. see Net_SFTP::_parseLongname() for more information.
|
520 |
+
// per the above comment, this is a shot in the dark that, on most servers, won't help us in determining
|
521 |
+
// the file type for Net_SFTP::stat() and Net_SFTP::lstat() but it's worth a shot.
|
522 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
523 |
+
$this->fileType = $this->_parseLongname($this->_string_shift($response, $length));
|
524 |
+
break;
|
525 |
+
case NET_SFTP_STATUS:
|
526 |
+
extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
|
527 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
528 |
+
return false;
|
529 |
+
default:
|
530 |
+
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS', E_USER_NOTICE);
|
531 |
+
return false;
|
532 |
+
}
|
533 |
+
|
534 |
+
// if $this->pwd isn't set than the only thing $realpath could be is for '.', which is pretty much guaranteed to
|
535 |
+
// be a bonafide directory
|
536 |
+
return $realpath . '/' . $file;
|
537 |
+
}
|
538 |
+
|
539 |
+
/**
|
540 |
+
* Changes the current directory
|
541 |
+
*
|
542 |
+
* @param String $dir
|
543 |
+
* @return Boolean
|
544 |
+
* @access public
|
545 |
+
*/
|
546 |
+
function chdir($dir)
|
547 |
+
{
|
548 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
549 |
+
return false;
|
550 |
+
}
|
551 |
+
|
552 |
+
if ($dir[strlen($dir) - 1] != '/') {
|
553 |
+
$dir.= '/';
|
554 |
+
}
|
555 |
+
$dir = $this->_realpath($dir);
|
556 |
+
|
557 |
+
// confirm that $dir is, in fact, a valid directory
|
558 |
+
if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
|
559 |
+
return false;
|
560 |
+
}
|
561 |
+
|
562 |
+
// see Net_SFTP::nlist() for a more thorough explanation of the following
|
563 |
+
$response = $this->_get_sftp_packet();
|
564 |
+
switch ($this->packet_type) {
|
565 |
+
case NET_SFTP_HANDLE:
|
566 |
+
$handle = substr($response, 4);
|
567 |
+
break;
|
568 |
+
case NET_SFTP_STATUS:
|
569 |
+
extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
|
570 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
571 |
+
return false;
|
572 |
+
default:
|
573 |
+
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
|
574 |
+
return false;
|
575 |
+
}
|
576 |
+
|
577 |
+
if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
|
578 |
+
return false;
|
579 |
+
}
|
580 |
+
|
581 |
+
$response = $this->_get_sftp_packet();
|
582 |
+
if ($this->packet_type != NET_SFTP_STATUS) {
|
583 |
+
user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
|
584 |
+
return false;
|
585 |
+
}
|
586 |
+
|
587 |
+
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
588 |
+
if ($status != NET_SFTP_STATUS_OK) {
|
589 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
590 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
591 |
+
return false;
|
592 |
+
}
|
593 |
+
|
594 |
+
$this->pwd = $dir;
|
595 |
+
return true;
|
596 |
+
}
|
597 |
+
|
598 |
+
/**
|
599 |
+
* Returns a list of files in the given directory
|
600 |
+
*
|
601 |
+
* @param optional String $dir
|
602 |
+
* @return Mixed
|
603 |
+
* @access public
|
604 |
+
*/
|
605 |
+
function nlist($dir = '.')
|
606 |
+
{
|
607 |
+
return $this->_list($dir, false);
|
608 |
+
}
|
609 |
+
|
610 |
+
/**
|
611 |
+
* Returns a detailed list of files in the given directory
|
612 |
+
*
|
613 |
+
* @param optional String $dir
|
614 |
+
* @return Mixed
|
615 |
+
* @access public
|
616 |
+
*/
|
617 |
+
function rawlist($dir = '.')
|
618 |
+
{
|
619 |
+
return $this->_list($dir, true);
|
620 |
+
}
|
621 |
+
|
622 |
+
/**
|
623 |
+
* Reads a list, be it detailed or not, of files in the given directory
|
624 |
+
*
|
625 |
+
* @param optional String $dir
|
626 |
+
* @return Mixed
|
627 |
+
* @access private
|
628 |
+
*/
|
629 |
+
function _list($dir, $raw = true)
|
630 |
+
{
|
631 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
632 |
+
return false;
|
633 |
+
}
|
634 |
+
|
635 |
+
$dir = $this->_realpath($dir);
|
636 |
+
if ($dir === false) {
|
637 |
+
return false;
|
638 |
+
}
|
639 |
+
|
640 |
+
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.2
|
641 |
+
if (!$this->_send_sftp_packet(NET_SFTP_OPENDIR, pack('Na*', strlen($dir), $dir))) {
|
642 |
+
return false;
|
643 |
+
}
|
644 |
+
|
645 |
+
$response = $this->_get_sftp_packet();
|
646 |
+
switch ($this->packet_type) {
|
647 |
+
case NET_SFTP_HANDLE:
|
648 |
+
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-9.2
|
649 |
+
// since 'handle' is the last field in the SSH_FXP_HANDLE packet, we'll just remove the first four bytes that
|
650 |
+
// represent the length of the string and leave it at that
|
651 |
+
$handle = substr($response, 4);
|
652 |
+
break;
|
653 |
+
case NET_SFTP_STATUS:
|
654 |
+
// presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
|
655 |
+
extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
|
656 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
657 |
+
return false;
|
658 |
+
default:
|
659 |
+
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
|
660 |
+
return false;
|
661 |
+
}
|
662 |
+
|
663 |
+
$contents = array();
|
664 |
+
while (true) {
|
665 |
+
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.2
|
666 |
+
// why multiple SSH_FXP_READDIR packets would be sent when the response to a single one can span arbitrarily many
|
667 |
+
// SSH_MSG_CHANNEL_DATA messages is not known to me.
|
668 |
+
if (!$this->_send_sftp_packet(NET_SFTP_READDIR, pack('Na*', strlen($handle), $handle))) {
|
669 |
+
return false;
|
670 |
+
}
|
671 |
+
|
672 |
+
$response = $this->_get_sftp_packet();
|
673 |
+
switch ($this->packet_type) {
|
674 |
+
case NET_SFTP_NAME:
|
675 |
+
extract(unpack('Ncount', $this->_string_shift($response, 4)));
|
676 |
+
for ($i = 0; $i < $count; $i++) {
|
677 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
678 |
+
$shortname = $this->_string_shift($response, $length);
|
679 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
680 |
+
$longname = $this->_string_shift($response, $length);
|
681 |
+
$attributes = $this->_parseAttributes($response); // we also don't care about the attributes
|
682 |
+
if (!$raw) {
|
683 |
+
$contents[] = $shortname;
|
684 |
+
} else {
|
685 |
+
$contents[$shortname] = $attributes;
|
686 |
+
$fileType = $this->_parseLongname($longname);
|
687 |
+
if ($fileType) {
|
688 |
+
$contents[$shortname]['type'] = $fileType;
|
689 |
+
}
|
690 |
+
}
|
691 |
+
// SFTPv6 has an optional boolean end-of-list field, but we'll ignore that, since the
|
692 |
+
// final SSH_FXP_STATUS packet should tell us that, already.
|
693 |
+
}
|
694 |
+
break;
|
695 |
+
case NET_SFTP_STATUS:
|
696 |
+
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
697 |
+
if ($status != NET_SFTP_STATUS_EOF) {
|
698 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
699 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
700 |
+
return false;
|
701 |
+
}
|
702 |
+
break 2;
|
703 |
+
default:
|
704 |
+
user_error('Expected SSH_FXP_NAME or SSH_FXP_STATUS', E_USER_NOTICE);
|
705 |
+
return false;
|
706 |
+
}
|
707 |
+
}
|
708 |
+
|
709 |
+
if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
|
710 |
+
return false;
|
711 |
+
}
|
712 |
+
|
713 |
+
// "The client MUST release all resources associated with the handle regardless of the status."
|
714 |
+
// -- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.1.3
|
715 |
+
$response = $this->_get_sftp_packet();
|
716 |
+
if ($this->packet_type != NET_SFTP_STATUS) {
|
717 |
+
user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
|
718 |
+
return false;
|
719 |
+
}
|
720 |
+
|
721 |
+
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
722 |
+
if ($status != NET_SFTP_STATUS_OK) {
|
723 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
724 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
725 |
+
return false;
|
726 |
+
}
|
727 |
+
|
728 |
+
return $contents;
|
729 |
+
}
|
730 |
+
|
731 |
+
/**
|
732 |
+
* Returns the file size, in bytes, or false, on failure
|
733 |
+
*
|
734 |
+
* Files larger than 4GB will show up as being exactly 4GB.
|
735 |
+
*
|
736 |
+
* @param String $filename
|
737 |
+
* @return Mixed
|
738 |
+
* @access public
|
739 |
+
*/
|
740 |
+
function size($filename)
|
741 |
+
{
|
742 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
743 |
+
return false;
|
744 |
+
}
|
745 |
+
|
746 |
+
$filename = $this->_realpath($filename);
|
747 |
+
if ($filename === false) {
|
748 |
+
return false;
|
749 |
+
}
|
750 |
+
|
751 |
+
return $this->_size($filename);
|
752 |
+
}
|
753 |
+
|
754 |
+
/**
|
755 |
+
* Returns general information about a file.
|
756 |
+
*
|
757 |
+
* Returns an array on success and false otherwise.
|
758 |
+
*
|
759 |
+
* @param String $filename
|
760 |
+
* @return Mixed
|
761 |
+
* @access public
|
762 |
+
*/
|
763 |
+
function stat($filename)
|
764 |
+
{
|
765 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
766 |
+
return false;
|
767 |
+
}
|
768 |
+
|
769 |
+
$filename = $this->_realpath($filename);
|
770 |
+
if ($filename === false) {
|
771 |
+
return false;
|
772 |
+
}
|
773 |
+
|
774 |
+
return $this->_stat($filename, NET_SFTP_STAT);
|
775 |
+
}
|
776 |
+
|
777 |
+
/**
|
778 |
+
* Returns general information about a file or symbolic link.
|
779 |
+
*
|
780 |
+
* Returns an array on success and false otherwise.
|
781 |
+
*
|
782 |
+
* @param String $filename
|
783 |
+
* @return Mixed
|
784 |
+
* @access public
|
785 |
+
*/
|
786 |
+
function lstat($filename)
|
787 |
+
{
|
788 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
789 |
+
return false;
|
790 |
+
}
|
791 |
+
|
792 |
+
$filename = $this->_realpath($filename);
|
793 |
+
if ($filename === false) {
|
794 |
+
return false;
|
795 |
+
}
|
796 |
+
|
797 |
+
return $this->_stat($filename, NET_SFTP_LSTAT);
|
798 |
+
}
|
799 |
+
|
800 |
+
/**
|
801 |
+
* Returns general information about a file or symbolic link
|
802 |
+
*
|
803 |
+
* Determines information without calling Net_SFTP::_realpath().
|
804 |
+
* The second parameter can be either NET_SFTP_STAT or NET_SFTP_LSTAT.
|
805 |
+
*
|
806 |
+
* @param String $filename
|
807 |
+
* @param Integer $type
|
808 |
+
* @return Mixed
|
809 |
+
* @access private
|
810 |
+
*/
|
811 |
+
function _stat($filename, $type)
|
812 |
+
{
|
813 |
+
// SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
|
814 |
+
$packet = pack('Na*', strlen($filename), $filename);
|
815 |
+
if (!$this->_send_sftp_packet($type, $packet)) {
|
816 |
+
return false;
|
817 |
+
}
|
818 |
+
|
819 |
+
$response = $this->_get_sftp_packet();
|
820 |
+
switch ($this->packet_type) {
|
821 |
+
case NET_SFTP_ATTRS:
|
822 |
+
$attributes = $this->_parseAttributes($response);
|
823 |
+
if ($this->fileType) {
|
824 |
+
$attributes['type'] = $this->fileType;
|
825 |
+
}
|
826 |
+
return $attributes;
|
827 |
+
case NET_SFTP_STATUS:
|
828 |
+
extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
|
829 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
830 |
+
return false;
|
831 |
+
}
|
832 |
+
|
833 |
+
user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS', E_USER_NOTICE);
|
834 |
+
return false;
|
835 |
+
}
|
836 |
+
|
837 |
+
/**
|
838 |
+
* Returns the file size, in bytes, or false, on failure
|
839 |
+
*
|
840 |
+
* Determines the size without calling Net_SFTP::_realpath()
|
841 |
+
*
|
842 |
+
* @param String $filename
|
843 |
+
* @return Mixed
|
844 |
+
* @access private
|
845 |
+
*/
|
846 |
+
function _size($filename)
|
847 |
+
{
|
848 |
+
$result = $this->_stat($filename, NET_SFTP_LSTAT);
|
849 |
+
return $result === false ? false : $result['size'];
|
850 |
+
}
|
851 |
+
|
852 |
+
/**
|
853 |
+
* Set permissions on a file.
|
854 |
+
*
|
855 |
+
* Returns the new file permissions on success or FALSE on error.
|
856 |
+
*
|
857 |
+
* @param Integer $mode
|
858 |
+
* @param String $filename
|
859 |
+
* @return Mixed
|
860 |
+
* @access public
|
861 |
+
*/
|
862 |
+
function chmod($mode, $filename)
|
863 |
+
{
|
864 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
865 |
+
return false;
|
866 |
+
}
|
867 |
+
|
868 |
+
$filename = $this->_realpath($filename);
|
869 |
+
if ($filename === false) {
|
870 |
+
return false;
|
871 |
+
}
|
872 |
+
|
873 |
+
// SFTPv4+ has an additional byte field - type - that would need to be sent, as well. setting it to
|
874 |
+
// SSH_FILEXFER_TYPE_UNKNOWN might work. if not, we'd have to do an SSH_FXP_STAT before doing an SSH_FXP_SETSTAT.
|
875 |
+
$attr = pack('N2', NET_SFTP_ATTR_PERMISSIONS, $mode & 07777);
|
876 |
+
if (!$this->_send_sftp_packet(NET_SFTP_SETSTAT, pack('Na*a*', strlen($filename), $filename, $attr))) {
|
877 |
+
return false;
|
878 |
+
}
|
879 |
+
|
880 |
+
/*
|
881 |
+
"Because some systems must use separate system calls to set various attributes, it is possible that a failure
|
882 |
+
response will be returned, but yet some of the attributes may be have been successfully modified. If possible,
|
883 |
+
servers SHOULD avoid this situation; however, clients MUST be aware that this is possible."
|
884 |
+
|
885 |
+
-- http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.6
|
886 |
+
*/
|
887 |
+
$response = $this->_get_sftp_packet();
|
888 |
+
if ($this->packet_type != NET_SFTP_STATUS) {
|
889 |
+
user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
|
890 |
+
return false;
|
891 |
+
}
|
892 |
+
|
893 |
+
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
894 |
+
if ($status != NET_SFTP_STATUS_EOF) {
|
895 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
896 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
897 |
+
}
|
898 |
+
|
899 |
+
// rather than return what the permissions *should* be, we'll return what they actually are. this will also
|
900 |
+
// tell us if the file actually exists.
|
901 |
+
// incidentally, SFTPv4+ adds an additional 32-bit integer field - flags - to the following:
|
902 |
+
$packet = pack('Na*', strlen($filename), $filename);
|
903 |
+
if (!$this->_send_sftp_packet(NET_SFTP_STAT, $packet)) {
|
904 |
+
return false;
|
905 |
+
}
|
906 |
+
|
907 |
+
$response = $this->_get_sftp_packet();
|
908 |
+
switch ($this->packet_type) {
|
909 |
+
case NET_SFTP_ATTRS:
|
910 |
+
$attrs = $this->_parseAttributes($response);
|
911 |
+
return $attrs['permissions'];
|
912 |
+
case NET_SFTP_STATUS:
|
913 |
+
extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
|
914 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
915 |
+
return false;
|
916 |
+
}
|
917 |
+
|
918 |
+
user_error('Expected SSH_FXP_ATTRS or SSH_FXP_STATUS', E_USER_NOTICE);
|
919 |
+
return false;
|
920 |
+
}
|
921 |
+
|
922 |
+
/**
|
923 |
+
* Creates a directory.
|
924 |
+
*
|
925 |
+
* @param String $dir
|
926 |
+
* @return Boolean
|
927 |
+
* @access public
|
928 |
+
*/
|
929 |
+
function mkdir($dir)
|
930 |
+
{
|
931 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
932 |
+
return false;
|
933 |
+
}
|
934 |
+
|
935 |
+
$dir = $this->_realpath(rtrim($dir, '/'));
|
936 |
+
if ($dir === false) {
|
937 |
+
return false;
|
938 |
+
}
|
939 |
+
|
940 |
+
// by not providing any permissions, hopefully the server will use the logged in users umask - their
|
941 |
+
// default permissions.
|
942 |
+
if (!$this->_send_sftp_packet(NET_SFTP_MKDIR, pack('Na*N', strlen($dir), $dir, 0))) {
|
943 |
+
return false;
|
944 |
+
}
|
945 |
+
|
946 |
+
$response = $this->_get_sftp_packet();
|
947 |
+
if ($this->packet_type != NET_SFTP_STATUS) {
|
948 |
+
user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
|
949 |
+
return false;
|
950 |
+
}
|
951 |
+
|
952 |
+
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
953 |
+
if ($status != NET_SFTP_STATUS_OK) {
|
954 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
955 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
956 |
+
return false;
|
957 |
+
}
|
958 |
+
|
959 |
+
return true;
|
960 |
+
}
|
961 |
+
|
962 |
+
/**
|
963 |
+
* Removes a directory.
|
964 |
+
*
|
965 |
+
* @param String $dir
|
966 |
+
* @return Boolean
|
967 |
+
* @access public
|
968 |
+
*/
|
969 |
+
function rmdir($dir)
|
970 |
+
{
|
971 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
972 |
+
return false;
|
973 |
+
}
|
974 |
+
|
975 |
+
$dir = $this->_realpath($dir);
|
976 |
+
if ($dir === false) {
|
977 |
+
return false;
|
978 |
+
}
|
979 |
+
|
980 |
+
if (!$this->_send_sftp_packet(NET_SFTP_RMDIR, pack('Na*', strlen($dir), $dir))) {
|
981 |
+
return false;
|
982 |
+
}
|
983 |
+
|
984 |
+
$response = $this->_get_sftp_packet();
|
985 |
+
if ($this->packet_type != NET_SFTP_STATUS) {
|
986 |
+
user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
|
987 |
+
return false;
|
988 |
+
}
|
989 |
+
|
990 |
+
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
991 |
+
if ($status != NET_SFTP_STATUS_OK) {
|
992 |
+
// presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED?
|
993 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
994 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
995 |
+
return false;
|
996 |
+
}
|
997 |
+
|
998 |
+
return true;
|
999 |
+
}
|
1000 |
+
|
1001 |
+
/**
|
1002 |
+
* Uploads a file to the SFTP server.
|
1003 |
+
*
|
1004 |
+
* By default, Net_SFTP::put() does not read from the local filesystem. $data is dumped directly into $remote_file.
|
1005 |
+
* So, for example, if you set $data to 'filename.ext' and then do Net_SFTP::get(), you will get a file, twelve bytes
|
1006 |
+
* long, containing 'filename.ext' as its contents.
|
1007 |
+
*
|
1008 |
+
* Setting $mode to NET_SFTP_LOCAL_FILE will change the above behavior. With NET_SFTP_LOCAL_FILE, $remote_file will
|
1009 |
+
* contain as many bytes as filename.ext does on your local filesystem. If your filename.ext is 1MB then that is how
|
1010 |
+
* large $remote_file will be, as well.
|
1011 |
+
*
|
1012 |
+
* Currently, only binary mode is supported. As such, if the line endings need to be adjusted, you will need to take
|
1013 |
+
* care of that, yourself.
|
1014 |
+
*
|
1015 |
+
* @param String $remote_file
|
1016 |
+
* @param String $data
|
1017 |
+
* @param optional Integer $mode
|
1018 |
+
* @return Boolean
|
1019 |
+
* @access public
|
1020 |
+
* @internal ASCII mode for SFTPv4/5/6 can be supported by adding a new function - Net_SFTP::setMode().
|
1021 |
+
*/
|
1022 |
+
function put($remote_file, $data, $mode = NET_SFTP_STRING)
|
1023 |
+
{
|
1024 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
1025 |
+
return false;
|
1026 |
+
}
|
1027 |
+
|
1028 |
+
$remote_file = $this->_realpath($remote_file);
|
1029 |
+
if ($remote_file === false) {
|
1030 |
+
return false;
|
1031 |
+
}
|
1032 |
+
|
1033 |
+
$packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_WRITE | NET_SFTP_OPEN_CREATE | NET_SFTP_OPEN_TRUNCATE, 0);
|
1034 |
+
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
|
1035 |
+
return false;
|
1036 |
+
}
|
1037 |
+
|
1038 |
+
$response = $this->_get_sftp_packet();
|
1039 |
+
switch ($this->packet_type) {
|
1040 |
+
case NET_SFTP_HANDLE:
|
1041 |
+
$handle = substr($response, 4);
|
1042 |
+
break;
|
1043 |
+
case NET_SFTP_STATUS:
|
1044 |
+
extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
|
1045 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
1046 |
+
return false;
|
1047 |
+
default:
|
1048 |
+
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
|
1049 |
+
return false;
|
1050 |
+
}
|
1051 |
+
|
1052 |
+
$initialize = true;
|
1053 |
+
|
1054 |
+
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.2.3
|
1055 |
+
if ($mode == NET_SFTP_LOCAL_FILE) {
|
1056 |
+
if (!is_file($data)) {
|
1057 |
+
user_error("$data is not a valid file", E_USER_NOTICE);
|
1058 |
+
return false;
|
1059 |
+
}
|
1060 |
+
$fp = @fopen($data, 'rb');
|
1061 |
+
if (!$fp) {
|
1062 |
+
return false;
|
1063 |
+
}
|
1064 |
+
$sent = 0;
|
1065 |
+
$size = filesize($data);
|
1066 |
+
} else {
|
1067 |
+
$sent = 0;
|
1068 |
+
$size = strlen($data);
|
1069 |
+
}
|
1070 |
+
|
1071 |
+
$size = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;
|
1072 |
+
|
1073 |
+
$sftp_packet_size = 4096; // PuTTY uses 4096
|
1074 |
+
$i = 0;
|
1075 |
+
while ($sent < $size) {
|
1076 |
+
$temp = $mode == NET_SFTP_LOCAL_FILE ? fread($fp, $sftp_packet_size) : $this->_string_shift($data, $sftp_packet_size);
|
1077 |
+
$packet = pack('Na*N3a*', strlen($handle), $handle, 0, $sent, strlen($temp), $temp);
|
1078 |
+
if (!$this->_send_sftp_packet(NET_SFTP_WRITE, $packet)) {
|
1079 |
+
fclose($fp);
|
1080 |
+
return false;
|
1081 |
+
}
|
1082 |
+
$sent+= strlen($temp);
|
1083 |
+
|
1084 |
+
$i++;
|
1085 |
+
|
1086 |
+
if ($i == 50) {
|
1087 |
+
if (!$this->_read_put_responses($i)) {
|
1088 |
+
$i = 0;
|
1089 |
+
break;
|
1090 |
+
}
|
1091 |
+
$i = 0;
|
1092 |
+
}
|
1093 |
+
}
|
1094 |
+
|
1095 |
+
$this->_read_put_responses($i);
|
1096 |
+
|
1097 |
+
if ($mode == NET_SFTP_LOCAL_FILE) {
|
1098 |
+
fclose($fp);
|
1099 |
+
}
|
1100 |
+
|
1101 |
+
if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
|
1102 |
+
return false;
|
1103 |
+
}
|
1104 |
+
|
1105 |
+
$response = $this->_get_sftp_packet();
|
1106 |
+
if ($this->packet_type != NET_SFTP_STATUS) {
|
1107 |
+
user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
|
1108 |
+
return false;
|
1109 |
+
}
|
1110 |
+
|
1111 |
+
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
1112 |
+
if ($status != NET_SFTP_STATUS_OK) {
|
1113 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1114 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
1115 |
+
return false;
|
1116 |
+
}
|
1117 |
+
|
1118 |
+
return true;
|
1119 |
+
}
|
1120 |
+
|
1121 |
+
/**
|
1122 |
+
* Reads multiple successive SSH_FXP_WRITE responses
|
1123 |
+
*
|
1124 |
+
* Sending an SSH_FXP_WRITE packet and immediately reading its response isn't as efficient as blindly sending out $i
|
1125 |
+
* SSH_FXP_WRITEs, in succession, and then reading $i responses.
|
1126 |
+
*
|
1127 |
+
* @param Integer $i
|
1128 |
+
* @return Boolean
|
1129 |
+
* @access private
|
1130 |
+
*/
|
1131 |
+
function _read_put_responses($i)
|
1132 |
+
{
|
1133 |
+
while ($i--) {
|
1134 |
+
$response = $this->_get_sftp_packet();
|
1135 |
+
if ($this->packet_type != NET_SFTP_STATUS) {
|
1136 |
+
user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
|
1137 |
+
return false;
|
1138 |
+
}
|
1139 |
+
|
1140 |
+
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
1141 |
+
if ($status != NET_SFTP_STATUS_OK) {
|
1142 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1143 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
1144 |
+
break;
|
1145 |
+
}
|
1146 |
+
}
|
1147 |
+
|
1148 |
+
return $i < 0;
|
1149 |
+
}
|
1150 |
+
|
1151 |
+
/**
|
1152 |
+
* Downloads a file from the SFTP server.
|
1153 |
+
*
|
1154 |
+
* Returns a string containing the contents of $remote_file if $local_file is left undefined or a boolean false if
|
1155 |
+
* the operation was unsuccessful. If $local_file is defined, returns true or false depending on the success of the
|
1156 |
+
* operation
|
1157 |
+
*
|
1158 |
+
* @param String $remote_file
|
1159 |
+
* @param optional String $local_file
|
1160 |
+
* @return Mixed
|
1161 |
+
* @access public
|
1162 |
+
*/
|
1163 |
+
function get($remote_file, $local_file = false)
|
1164 |
+
{
|
1165 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
1166 |
+
return false;
|
1167 |
+
}
|
1168 |
+
|
1169 |
+
$remote_file = $this->_realpath($remote_file);
|
1170 |
+
if ($remote_file === false) {
|
1171 |
+
return false;
|
1172 |
+
}
|
1173 |
+
|
1174 |
+
$size = $this->_size($remote_file);
|
1175 |
+
if ($size === false) {
|
1176 |
+
return false;
|
1177 |
+
}
|
1178 |
+
|
1179 |
+
$packet = pack('Na*N2', strlen($remote_file), $remote_file, NET_SFTP_OPEN_READ, 0);
|
1180 |
+
if (!$this->_send_sftp_packet(NET_SFTP_OPEN, $packet)) {
|
1181 |
+
return false;
|
1182 |
+
}
|
1183 |
+
|
1184 |
+
$response = $this->_get_sftp_packet();
|
1185 |
+
switch ($this->packet_type) {
|
1186 |
+
case NET_SFTP_HANDLE:
|
1187 |
+
$handle = substr($response, 4);
|
1188 |
+
break;
|
1189 |
+
case NET_SFTP_STATUS: // presumably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
|
1190 |
+
extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
|
1191 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
1192 |
+
return false;
|
1193 |
+
default:
|
1194 |
+
user_error('Expected SSH_FXP_HANDLE or SSH_FXP_STATUS', E_USER_NOTICE);
|
1195 |
+
return false;
|
1196 |
+
}
|
1197 |
+
|
1198 |
+
if ($local_file !== false) {
|
1199 |
+
$fp = fopen($local_file, 'wb');
|
1200 |
+
if (!$fp) {
|
1201 |
+
return false;
|
1202 |
+
}
|
1203 |
+
} else {
|
1204 |
+
$content = '';
|
1205 |
+
}
|
1206 |
+
|
1207 |
+
$read = 0;
|
1208 |
+
while ($read < $size) {
|
1209 |
+
$packet = pack('Na*N3', strlen($handle), $handle, 0, $read, 1 << 20);
|
1210 |
+
if (!$this->_send_sftp_packet(NET_SFTP_READ, $packet)) {
|
1211 |
+
return false;
|
1212 |
+
}
|
1213 |
+
|
1214 |
+
$response = $this->_get_sftp_packet();
|
1215 |
+
switch ($this->packet_type) {
|
1216 |
+
case NET_SFTP_DATA:
|
1217 |
+
$temp = substr($response, 4);
|
1218 |
+
$read+= strlen($temp);
|
1219 |
+
if ($local_file === false) {
|
1220 |
+
$content.= $temp;
|
1221 |
+
} else {
|
1222 |
+
fputs($fp, $temp);
|
1223 |
+
}
|
1224 |
+
break;
|
1225 |
+
case NET_SFTP_STATUS:
|
1226 |
+
extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
|
1227 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
1228 |
+
break 2;
|
1229 |
+
default:
|
1230 |
+
user_error('Expected SSH_FXP_DATA or SSH_FXP_STATUS', E_USER_NOTICE);
|
1231 |
+
return false;
|
1232 |
+
}
|
1233 |
+
}
|
1234 |
+
|
1235 |
+
if (!$this->_send_sftp_packet(NET_SFTP_CLOSE, pack('Na*', strlen($handle), $handle))) {
|
1236 |
+
return false;
|
1237 |
+
}
|
1238 |
+
|
1239 |
+
$response = $this->_get_sftp_packet();
|
1240 |
+
if ($this->packet_type != NET_SFTP_STATUS) {
|
1241 |
+
user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
|
1242 |
+
return false;
|
1243 |
+
}
|
1244 |
+
|
1245 |
+
extract(unpack('Nstatus/Nlength', $this->_string_shift($response, 8)));
|
1246 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
1247 |
+
|
1248 |
+
// check the status from the NET_SFTP_STATUS case in the above switch after the file has been closed
|
1249 |
+
if ($status != NET_SFTP_STATUS_OK) {
|
1250 |
+
return false;
|
1251 |
+
}
|
1252 |
+
|
1253 |
+
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
1254 |
+
if ($status != NET_SFTP_STATUS_OK) {
|
1255 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1256 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
1257 |
+
return false;
|
1258 |
+
}
|
1259 |
+
|
1260 |
+
if (isset($content)) {
|
1261 |
+
return $content;
|
1262 |
+
}
|
1263 |
+
|
1264 |
+
fclose($fp);
|
1265 |
+
return true;
|
1266 |
+
}
|
1267 |
+
|
1268 |
+
/**
|
1269 |
+
* Deletes a file on the SFTP server.
|
1270 |
+
*
|
1271 |
+
* @param String $path
|
1272 |
+
* @return Boolean
|
1273 |
+
* @access public
|
1274 |
+
*/
|
1275 |
+
function delete($path)
|
1276 |
+
{
|
1277 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
1278 |
+
return false;
|
1279 |
+
}
|
1280 |
+
|
1281 |
+
$path = $this->_realpath($path);
|
1282 |
+
if ($path === false) {
|
1283 |
+
return false;
|
1284 |
+
}
|
1285 |
+
|
1286 |
+
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
|
1287 |
+
if (!$this->_send_sftp_packet(NET_SFTP_REMOVE, pack('Na*', strlen($path), $path))) {
|
1288 |
+
return false;
|
1289 |
+
}
|
1290 |
+
|
1291 |
+
$response = $this->_get_sftp_packet();
|
1292 |
+
if ($this->packet_type != NET_SFTP_STATUS) {
|
1293 |
+
user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
|
1294 |
+
return false;
|
1295 |
+
}
|
1296 |
+
|
1297 |
+
// if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
|
1298 |
+
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
1299 |
+
if ($status != NET_SFTP_STATUS_OK) {
|
1300 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1301 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
1302 |
+
return false;
|
1303 |
+
}
|
1304 |
+
|
1305 |
+
return true;
|
1306 |
+
}
|
1307 |
+
|
1308 |
+
/**
|
1309 |
+
* Renames a file or a directory on the SFTP server
|
1310 |
+
*
|
1311 |
+
* @param String $oldname
|
1312 |
+
* @param String $newname
|
1313 |
+
* @return Boolean
|
1314 |
+
* @access public
|
1315 |
+
*/
|
1316 |
+
function rename($oldname, $newname)
|
1317 |
+
{
|
1318 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
1319 |
+
return false;
|
1320 |
+
}
|
1321 |
+
|
1322 |
+
$oldname = $this->_realpath($oldname);
|
1323 |
+
$newname = $this->_realpath($newname);
|
1324 |
+
if ($oldname === false || $newname === false) {
|
1325 |
+
return false;
|
1326 |
+
}
|
1327 |
+
|
1328 |
+
// http://tools.ietf.org/html/draft-ietf-secsh-filexfer-13#section-8.3
|
1329 |
+
$packet = pack('Na*Na*', strlen($oldname), $oldname, strlen($newname), $newname);
|
1330 |
+
if (!$this->_send_sftp_packet(NET_SFTP_RENAME, $packet)) {
|
1331 |
+
return false;
|
1332 |
+
}
|
1333 |
+
|
1334 |
+
$response = $this->_get_sftp_packet();
|
1335 |
+
if ($this->packet_type != NET_SFTP_STATUS) {
|
1336 |
+
user_error('Expected SSH_FXP_STATUS', E_USER_NOTICE);
|
1337 |
+
return false;
|
1338 |
+
}
|
1339 |
+
|
1340 |
+
// if $status isn't SSH_FX_OK it's probably SSH_FX_NO_SUCH_FILE or SSH_FX_PERMISSION_DENIED
|
1341 |
+
extract(unpack('Nstatus', $this->_string_shift($response, 4)));
|
1342 |
+
if ($status != NET_SFTP_STATUS_OK) {
|
1343 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1344 |
+
$this->sftp_errors[] = $this->status_codes[$status] . ': ' . $this->_string_shift($response, $length);
|
1345 |
+
return false;
|
1346 |
+
}
|
1347 |
+
|
1348 |
+
return true;
|
1349 |
+
}
|
1350 |
+
|
1351 |
+
/**
|
1352 |
+
* Parse Attributes
|
1353 |
+
*
|
1354 |
+
* See '7. File Attributes' of draft-ietf-secsh-filexfer-13 for more info.
|
1355 |
+
*
|
1356 |
+
* @param String $response
|
1357 |
+
* @return Array
|
1358 |
+
* @access private
|
1359 |
+
*/
|
1360 |
+
function _parseAttributes(&$response)
|
1361 |
+
{
|
1362 |
+
$attr = array();
|
1363 |
+
extract(unpack('Nflags', $this->_string_shift($response, 4)));
|
1364 |
+
// SFTPv4+ have a type field (a byte) that follows the above flag field
|
1365 |
+
foreach ($this->attributes as $key => $value) {
|
1366 |
+
switch ($flags & $key) {
|
1367 |
+
case NET_SFTP_ATTR_SIZE: // 0x00000001
|
1368 |
+
// size is represented by a 64-bit integer, so we perhaps ought to be doing the following:
|
1369 |
+
// $attr['size'] = new Math_BigInteger($this->_string_shift($response, 8), 256);
|
1370 |
+
// of course, you shouldn't be using Net_SFTP to transfer files that are in excess of 4GB
|
1371 |
+
// (0xFFFFFFFF bytes), anyway. as such, we'll just represent all file sizes that are bigger than
|
1372 |
+
// 4GB as being 4GB.
|
1373 |
+
extract(unpack('Nupper/Nsize', $this->_string_shift($response, 8)));
|
1374 |
+
if ($upper) {
|
1375 |
+
$attr['size'] = 0xFFFFFFFF;
|
1376 |
+
} else {
|
1377 |
+
$attr['size'] = $size < 0 ? ($size & 0x7FFFFFFF) + 0x80000000 : $size;
|
1378 |
+
}
|
1379 |
+
break;
|
1380 |
+
case NET_SFTP_ATTR_UIDGID: // 0x00000002 (SFTPv3 only)
|
1381 |
+
$attr+= unpack('Nuid/Ngid', $this->_string_shift($response, 8));
|
1382 |
+
break;
|
1383 |
+
case NET_SFTP_ATTR_PERMISSIONS: // 0x00000004
|
1384 |
+
$attr+= unpack('Npermissions', $this->_string_shift($response, 4));
|
1385 |
+
break;
|
1386 |
+
case NET_SFTP_ATTR_ACCESSTIME: // 0x00000008
|
1387 |
+
$attr+= unpack('Natime/Nmtime', $this->_string_shift($response, 8));
|
1388 |
+
break;
|
1389 |
+
case NET_SFTP_ATTR_EXTENDED: // 0x80000000
|
1390 |
+
extract(unpack('Ncount', $this->_string_shift($response, 4)));
|
1391 |
+
for ($i = 0; $i < $count; $i++) {
|
1392 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1393 |
+
$key = $this->_string_shift($response, $length);
|
1394 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1395 |
+
$attr[$key] = $this->_string_shift($response, $length);
|
1396 |
+
}
|
1397 |
+
}
|
1398 |
+
}
|
1399 |
+
return $attr;
|
1400 |
+
}
|
1401 |
+
|
1402 |
+
/**
|
1403 |
+
* Parse Longname
|
1404 |
+
*
|
1405 |
+
* SFTPv3 doesn't provide any easy way of identifying a file type. You could try to open
|
1406 |
+
* a file as a directory and see if an error is returned or you could try to parse the
|
1407 |
+
* SFTPv3-specific longname field of the SSH_FXP_NAME packet. That's what this function does.
|
1408 |
+
* The result is returned using the
|
1409 |
+
* {@link http://tools.ietf.org/html/draft-ietf-secsh-filexfer-04#section-5.2 SFTPv4 type constants}.
|
1410 |
+
*
|
1411 |
+
* If the longname is in an unrecognized format bool(false) is returned.
|
1412 |
+
*
|
1413 |
+
* @param String $longname
|
1414 |
+
* @return Mixed
|
1415 |
+
* @access private
|
1416 |
+
*/
|
1417 |
+
function _parseLongname($longname)
|
1418 |
+
{
|
1419 |
+
// http://en.wikipedia.org/wiki/Unix_file_types
|
1420 |
+
if (preg_match('#^[^/]([r-][w-][x-]){3}#', $longname)) {
|
1421 |
+
switch ($longname[0]) {
|
1422 |
+
case '-':
|
1423 |
+
return NET_SFTP_TYPE_REGULAR;
|
1424 |
+
case 'd':
|
1425 |
+
return NET_SFTP_TYPE_DIRECTORY;
|
1426 |
+
case 'l':
|
1427 |
+
return NET_SFTP_TYPE_SYMLINK;
|
1428 |
+
default:
|
1429 |
+
return NET_SFTP_TYPE_SPECIAL;
|
1430 |
+
}
|
1431 |
+
}
|
1432 |
+
|
1433 |
+
return false;
|
1434 |
+
}
|
1435 |
+
|
1436 |
+
/**
|
1437 |
+
* Sends SFTP Packets
|
1438 |
+
*
|
1439 |
+
* See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info.
|
1440 |
+
*
|
1441 |
+
* @param Integer $type
|
1442 |
+
* @param String $data
|
1443 |
+
* @see Net_SFTP::_get_sftp_packet()
|
1444 |
+
* @see Net_SSH2::_send_channel_packet()
|
1445 |
+
* @return Boolean
|
1446 |
+
* @access private
|
1447 |
+
*/
|
1448 |
+
function _send_sftp_packet($type, $data)
|
1449 |
+
{
|
1450 |
+
$packet = $this->request_id !== false ?
|
1451 |
+
pack('NCNa*', strlen($data) + 5, $type, $this->request_id, $data) :
|
1452 |
+
pack('NCa*', strlen($data) + 1, $type, $data);
|
1453 |
+
|
1454 |
+
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
|
1455 |
+
$result = $this->_send_channel_packet(NET_SFTP_CHANNEL, $packet);
|
1456 |
+
$stop = strtok(microtime(), ' ') + strtok('');
|
1457 |
+
|
1458 |
+
if (defined('NET_SFTP_LOGGING')) {
|
1459 |
+
$this->packet_type_log[] = '-> ' . $this->packet_types[$type] .
|
1460 |
+
' (' . round($stop - $start, 4) . 's)';
|
1461 |
+
if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
|
1462 |
+
$this->packet_log[] = $data;
|
1463 |
+
}
|
1464 |
+
}
|
1465 |
+
|
1466 |
+
return $result;
|
1467 |
+
}
|
1468 |
+
|
1469 |
+
/**
|
1470 |
+
* Receives SFTP Packets
|
1471 |
+
*
|
1472 |
+
* See '6. General Packet Format' of draft-ietf-secsh-filexfer-13 for more info.
|
1473 |
+
*
|
1474 |
+
* Incidentally, the number of SSH_MSG_CHANNEL_DATA messages has no bearing on the number of SFTP packets present.
|
1475 |
+
* There can be one SSH_MSG_CHANNEL_DATA messages containing two SFTP packets or there can be two SSH_MSG_CHANNEL_DATA
|
1476 |
+
* messages containing one SFTP packet.
|
1477 |
+
*
|
1478 |
+
* @see Net_SFTP::_send_sftp_packet()
|
1479 |
+
* @return String
|
1480 |
+
* @access private
|
1481 |
+
*/
|
1482 |
+
function _get_sftp_packet()
|
1483 |
+
{
|
1484 |
+
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
|
1485 |
+
|
1486 |
+
// SFTP packet length
|
1487 |
+
while (strlen($this->packet_buffer) < 4) {
|
1488 |
+
$temp = $this->_get_channel_packet(NET_SFTP_CHANNEL);
|
1489 |
+
if (is_bool($temp)) {
|
1490 |
+
$this->packet_type = false;
|
1491 |
+
$this->packet_buffer = '';
|
1492 |
+
return false;
|
1493 |
+
}
|
1494 |
+
$this->packet_buffer.= $temp;
|
1495 |
+
}
|
1496 |
+
extract(unpack('Nlength', $this->_string_shift($this->packet_buffer, 4)));
|
1497 |
+
$tempLength = $length;
|
1498 |
+
$tempLength-= strlen($this->packet_buffer);
|
1499 |
+
|
1500 |
+
// SFTP packet type and data payload
|
1501 |
+
while ($tempLength > 0) {
|
1502 |
+
$temp = $this->_get_channel_packet(NET_SFTP_CHANNEL);
|
1503 |
+
if (is_bool($temp)) {
|
1504 |
+
$this->packet_type = false;
|
1505 |
+
$this->packet_buffer = '';
|
1506 |
+
return false;
|
1507 |
+
}
|
1508 |
+
$this->packet_buffer.= $temp;
|
1509 |
+
$tempLength-= strlen($temp);
|
1510 |
+
}
|
1511 |
+
|
1512 |
+
$stop = strtok(microtime(), ' ') + strtok('');
|
1513 |
+
|
1514 |
+
$this->packet_type = ord($this->_string_shift($this->packet_buffer));
|
1515 |
+
|
1516 |
+
if ($this->request_id !== false) {
|
1517 |
+
$this->_string_shift($this->packet_buffer, 4); // remove the request id
|
1518 |
+
$length-= 5; // account for the request id and the packet type
|
1519 |
+
} else {
|
1520 |
+
$length-= 1; // account for the packet type
|
1521 |
+
}
|
1522 |
+
|
1523 |
+
$packet = $this->_string_shift($this->packet_buffer, $length);
|
1524 |
+
|
1525 |
+
if (defined('NET_SFTP_LOGGING')) {
|
1526 |
+
$this->packet_type_log[] = '<- ' . $this->packet_types[$this->packet_type] .
|
1527 |
+
' (' . round($stop - $start, 4) . 's)';
|
1528 |
+
if (NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX) {
|
1529 |
+
$this->packet_log[] = $packet;
|
1530 |
+
}
|
1531 |
+
}
|
1532 |
+
|
1533 |
+
return $packet;
|
1534 |
+
}
|
1535 |
+
|
1536 |
+
/**
|
1537 |
+
* Returns a log of the packets that have been sent and received.
|
1538 |
+
*
|
1539 |
+
* Returns a string if NET_SFTP_LOGGING == NET_SFTP_LOG_COMPLEX, an array if NET_SFTP_LOGGING == NET_SFTP_LOG_SIMPLE and false if !defined('NET_SFTP_LOGGING')
|
1540 |
+
*
|
1541 |
+
* @access public
|
1542 |
+
* @return String or Array
|
1543 |
+
*/
|
1544 |
+
function getSFTPLog()
|
1545 |
+
{
|
1546 |
+
if (!defined('NET_SFTP_LOGGING')) {
|
1547 |
+
return false;
|
1548 |
+
}
|
1549 |
+
|
1550 |
+
switch (NET_SFTP_LOGGING) {
|
1551 |
+
case NET_SFTP_LOG_COMPLEX:
|
1552 |
+
return $this->_format_log($this->packet_log, $this->packet_type_log);
|
1553 |
+
break;
|
1554 |
+
//case NET_SFTP_LOG_SIMPLE:
|
1555 |
+
default:
|
1556 |
+
return $this->packet_type_log;
|
1557 |
+
}
|
1558 |
+
}
|
1559 |
+
|
1560 |
+
/**
|
1561 |
+
* Returns all errors
|
1562 |
+
*
|
1563 |
+
* @return String
|
1564 |
+
* @access public
|
1565 |
+
*/
|
1566 |
+
function getSFTPErrors()
|
1567 |
+
{
|
1568 |
+
return $this->sftp_errors;
|
1569 |
+
}
|
1570 |
+
|
1571 |
+
/**
|
1572 |
+
* Returns the last error
|
1573 |
+
*
|
1574 |
+
* @return String
|
1575 |
+
* @access public
|
1576 |
+
*/
|
1577 |
+
function getLastSFTPError()
|
1578 |
+
{
|
1579 |
+
return count($this->sftp_errors) ? $this->sftp_errors[count($this->sftp_errors) - 1] : '';
|
1580 |
+
}
|
1581 |
+
|
1582 |
+
/**
|
1583 |
+
* Get supported SFTP versions
|
1584 |
+
*
|
1585 |
+
* @return Array
|
1586 |
+
* @access public
|
1587 |
+
*/
|
1588 |
+
function getSupportedVersions()
|
1589 |
+
{
|
1590 |
+
$temp = array('version' => $this->version);
|
1591 |
+
if (isset($this->extensions['versions'])) {
|
1592 |
+
$temp['extensions'] = $this->extensions['versions'];
|
1593 |
+
}
|
1594 |
+
return $temp;
|
1595 |
+
}
|
1596 |
+
|
1597 |
+
/**
|
1598 |
+
* Disconnect
|
1599 |
+
*
|
1600 |
+
* @param Integer $reason
|
1601 |
+
* @return Boolean
|
1602 |
+
* @access private
|
1603 |
+
*/
|
1604 |
+
function _disconnect($reason)
|
1605 |
+
{
|
1606 |
+
$this->pwd = false;
|
1607 |
+
parent::_disconnect($reason);
|
1608 |
+
}
|
1609 |
+
}
|
classes/phpseclib/Net/SSH1.php
ADDED
@@ -0,0 +1,1408 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of SSHv1.
|
6 |
+
*
|
7 |
+
* PHP versions 4 and 5
|
8 |
+
*
|
9 |
+
* Here's a short example of how to use this library:
|
10 |
+
* <code>
|
11 |
+
* <?php
|
12 |
+
* include('Net/SSH1.php');
|
13 |
+
*
|
14 |
+
* $ssh = new Net_SSH1('www.domain.tld');
|
15 |
+
* if (!$ssh->login('username', 'password')) {
|
16 |
+
* exit('Login Failed');
|
17 |
+
* }
|
18 |
+
*
|
19 |
+
* echo $ssh->exec('ls -la');
|
20 |
+
* ?>
|
21 |
+
* </code>
|
22 |
+
*
|
23 |
+
* Here's another short example:
|
24 |
+
* <code>
|
25 |
+
* <?php
|
26 |
+
* include('Net/SSH1.php');
|
27 |
+
*
|
28 |
+
* $ssh = new Net_SSH1('www.domain.tld');
|
29 |
+
* if (!$ssh->login('username', 'password')) {
|
30 |
+
* exit('Login Failed');
|
31 |
+
* }
|
32 |
+
*
|
33 |
+
* echo $ssh->read('username@username:~$');
|
34 |
+
* $ssh->write("ls -la\n");
|
35 |
+
* echo $ssh->read('username@username:~$');
|
36 |
+
* ?>
|
37 |
+
* </code>
|
38 |
+
*
|
39 |
+
* More information on the SSHv1 specification can be found by reading
|
40 |
+
* {@link http://www.snailbook.com/docs/protocol-1.5.txt protocol-1.5.txt}.
|
41 |
+
*
|
42 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
43 |
+
* of this software and associated documentation files (the "Software"), to deal
|
44 |
+
* in the Software without restriction, including without limitation the rights
|
45 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
46 |
+
* copies of the Software, and to permit persons to whom the Software is
|
47 |
+
* furnished to do so, subject to the following conditions:
|
48 |
+
*
|
49 |
+
* The above copyright notice and this permission notice shall be included in
|
50 |
+
* all copies or substantial portions of the Software.
|
51 |
+
*
|
52 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
53 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
54 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
55 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
56 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
57 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
58 |
+
* THE SOFTWARE.
|
59 |
+
*
|
60 |
+
* @category Net
|
61 |
+
* @package Net_SSH1
|
62 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
63 |
+
* @copyright MMVII Jim Wigginton
|
64 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
65 |
+
* @version $Id: SSH1.php,v 1.15 2010/03/22 22:01:38 terrafrost Exp $
|
66 |
+
* @link http://phpseclib.sourceforge.net
|
67 |
+
*/
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Include Math_BigInteger
|
71 |
+
*
|
72 |
+
* Used to do RSA encryption.
|
73 |
+
*/
|
74 |
+
require_once('Math/BigInteger.php');
|
75 |
+
|
76 |
+
/**
|
77 |
+
* Include Crypt_Null
|
78 |
+
*/
|
79 |
+
//require_once('Crypt/Null.php');
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Include Crypt_DES
|
83 |
+
*/
|
84 |
+
require_once('Crypt/DES.php');
|
85 |
+
|
86 |
+
/**
|
87 |
+
* Include Crypt_TripleDES
|
88 |
+
*/
|
89 |
+
require_once('Crypt/TripleDES.php');
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Include Crypt_RC4
|
93 |
+
*/
|
94 |
+
require_once('Crypt/RC4.php');
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Include Crypt_Random
|
98 |
+
*/
|
99 |
+
require_once('Crypt/Random.php');
|
100 |
+
|
101 |
+
/**#@+
|
102 |
+
* Encryption Methods
|
103 |
+
*
|
104 |
+
* @see Net_SSH1::getSupportedCiphers()
|
105 |
+
* @access public
|
106 |
+
*/
|
107 |
+
/**
|
108 |
+
* No encryption
|
109 |
+
*
|
110 |
+
* Not supported.
|
111 |
+
*/
|
112 |
+
define('NET_SSH1_CIPHER_NONE', 0);
|
113 |
+
/**
|
114 |
+
* IDEA in CFB mode
|
115 |
+
*
|
116 |
+
* Not supported.
|
117 |
+
*/
|
118 |
+
define('NET_SSH1_CIPHER_IDEA', 1);
|
119 |
+
/**
|
120 |
+
* DES in CBC mode
|
121 |
+
*/
|
122 |
+
define('NET_SSH1_CIPHER_DES', 2);
|
123 |
+
/**
|
124 |
+
* Triple-DES in CBC mode
|
125 |
+
*
|
126 |
+
* All implementations are required to support this
|
127 |
+
*/
|
128 |
+
define('NET_SSH1_CIPHER_3DES', 3);
|
129 |
+
/**
|
130 |
+
* TRI's Simple Stream encryption CBC
|
131 |
+
*
|
132 |
+
* Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, does define it (see cipher.h),
|
133 |
+
* although it doesn't use it (see cipher.c)
|
134 |
+
*/
|
135 |
+
define('NET_SSH1_CIPHER_BROKEN_TSS', 4);
|
136 |
+
/**
|
137 |
+
* RC4
|
138 |
+
*
|
139 |
+
* Not supported.
|
140 |
+
*
|
141 |
+
* @internal According to the SSH1 specs:
|
142 |
+
*
|
143 |
+
* "The first 16 bytes of the session key are used as the key for
|
144 |
+
* the server to client direction. The remaining 16 bytes are used
|
145 |
+
* as the key for the client to server direction. This gives
|
146 |
+
* independent 128-bit keys for each direction."
|
147 |
+
*
|
148 |
+
* This library currently only supports encryption when the same key is being used for both directions. This is
|
149 |
+
* because there's only one $crypto object. Two could be added ($encrypt and $decrypt, perhaps).
|
150 |
+
*/
|
151 |
+
define('NET_SSH1_CIPHER_RC4', 5);
|
152 |
+
/**
|
153 |
+
* Blowfish
|
154 |
+
*
|
155 |
+
* Not supported nor is it defined in the official SSH1 specs. OpenSSH, however, defines it (see cipher.h) and
|
156 |
+
* uses it (see cipher.c)
|
157 |
+
*/
|
158 |
+
define('NET_SSH1_CIPHER_BLOWFISH', 6);
|
159 |
+
/**#@-*/
|
160 |
+
|
161 |
+
/**#@+
|
162 |
+
* Authentication Methods
|
163 |
+
*
|
164 |
+
* @see Net_SSH1::getSupportedAuthentications()
|
165 |
+
* @access public
|
166 |
+
*/
|
167 |
+
/**
|
168 |
+
* .rhosts or /etc/hosts.equiv
|
169 |
+
*/
|
170 |
+
define('NET_SSH1_AUTH_RHOSTS', 1);
|
171 |
+
/**
|
172 |
+
* pure RSA authentication
|
173 |
+
*/
|
174 |
+
define('NET_SSH1_AUTH_RSA', 2);
|
175 |
+
/**
|
176 |
+
* password authentication
|
177 |
+
*
|
178 |
+
* This is the only method that is supported by this library.
|
179 |
+
*/
|
180 |
+
define('NET_SSH1_AUTH_PASSWORD', 3);
|
181 |
+
/**
|
182 |
+
* .rhosts with RSA host authentication
|
183 |
+
*/
|
184 |
+
define('NET_SSH1_AUTH_RHOSTS_RSA', 4);
|
185 |
+
/**#@-*/
|
186 |
+
|
187 |
+
/**#@+
|
188 |
+
* Terminal Modes
|
189 |
+
*
|
190 |
+
* @link http://3sp.com/content/developer/maverick-net/docs/Maverick.SSH.PseudoTerminalModesMembers.html
|
191 |
+
* @access private
|
192 |
+
*/
|
193 |
+
define('NET_SSH1_TTY_OP_END', 0);
|
194 |
+
/**#@-*/
|
195 |
+
|
196 |
+
/**
|
197 |
+
* The Response Type
|
198 |
+
*
|
199 |
+
* @see Net_SSH1::_get_binary_packet()
|
200 |
+
* @access private
|
201 |
+
*/
|
202 |
+
define('NET_SSH1_RESPONSE_TYPE', 1);
|
203 |
+
|
204 |
+
/**
|
205 |
+
* The Response Data
|
206 |
+
*
|
207 |
+
* @see Net_SSH1::_get_binary_packet()
|
208 |
+
* @access private
|
209 |
+
*/
|
210 |
+
define('NET_SSH1_RESPONSE_DATA', 2);
|
211 |
+
|
212 |
+
/**#@+
|
213 |
+
* Execution Bitmap Masks
|
214 |
+
*
|
215 |
+
* @see Net_SSH1::bitmap
|
216 |
+
* @access private
|
217 |
+
*/
|
218 |
+
define('NET_SSH1_MASK_CONSTRUCTOR', 0x00000001);
|
219 |
+
define('NET_SSH1_MASK_LOGIN', 0x00000002);
|
220 |
+
define('NET_SSH1_MASK_SHELL', 0x00000004);
|
221 |
+
/**#@-*/
|
222 |
+
|
223 |
+
/**#@+
|
224 |
+
* @access public
|
225 |
+
* @see Net_SSH1::getLog()
|
226 |
+
*/
|
227 |
+
/**
|
228 |
+
* Returns the message numbers
|
229 |
+
*/
|
230 |
+
define('NET_SSH1_LOG_SIMPLE', 1);
|
231 |
+
/**
|
232 |
+
* Returns the message content
|
233 |
+
*/
|
234 |
+
define('NET_SSH1_LOG_COMPLEX', 2);
|
235 |
+
/**#@-*/
|
236 |
+
|
237 |
+
/**#@+
|
238 |
+
* @access public
|
239 |
+
* @see Net_SSH1::read()
|
240 |
+
*/
|
241 |
+
/**
|
242 |
+
* Returns when a string matching $expect exactly is found
|
243 |
+
*/
|
244 |
+
define('NET_SSH1_READ_SIMPLE', 1);
|
245 |
+
/**
|
246 |
+
* Returns when a string matching the regular expression $expect is found
|
247 |
+
*/
|
248 |
+
define('NET_SSH1_READ_REGEX', 2);
|
249 |
+
/**#@-*/
|
250 |
+
|
251 |
+
/**
|
252 |
+
* Pure-PHP implementation of SSHv1.
|
253 |
+
*
|
254 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
255 |
+
* @version 0.1.0
|
256 |
+
* @access public
|
257 |
+
* @package Net_SSH1
|
258 |
+
*/
|
259 |
+
class Net_SSH1 {
|
260 |
+
/**
|
261 |
+
* The SSH identifier
|
262 |
+
*
|
263 |
+
* @var String
|
264 |
+
* @access private
|
265 |
+
*/
|
266 |
+
var $identifier = 'SSH-1.5-phpseclib';
|
267 |
+
|
268 |
+
/**
|
269 |
+
* The Socket Object
|
270 |
+
*
|
271 |
+
* @var Object
|
272 |
+
* @access private
|
273 |
+
*/
|
274 |
+
var $fsock;
|
275 |
+
|
276 |
+
/**
|
277 |
+
* The cryptography object
|
278 |
+
*
|
279 |
+
* @var Object
|
280 |
+
* @access private
|
281 |
+
*/
|
282 |
+
var $crypto = false;
|
283 |
+
|
284 |
+
/**
|
285 |
+
* Execution Bitmap
|
286 |
+
*
|
287 |
+
* The bits that are set represent functions that have been called already. This is used to determine
|
288 |
+
* if a requisite function has been successfully executed. If not, an error should be thrown.
|
289 |
+
*
|
290 |
+
* @var Integer
|
291 |
+
* @access private
|
292 |
+
*/
|
293 |
+
var $bitmap = 0;
|
294 |
+
|
295 |
+
/**
|
296 |
+
* The Server Key Public Exponent
|
297 |
+
*
|
298 |
+
* Logged for debug purposes
|
299 |
+
*
|
300 |
+
* @see Net_SSH1::getServerKeyPublicExponent()
|
301 |
+
* @var String
|
302 |
+
* @access private
|
303 |
+
*/
|
304 |
+
var $server_key_public_exponent;
|
305 |
+
|
306 |
+
/**
|
307 |
+
* The Server Key Public Modulus
|
308 |
+
*
|
309 |
+
* Logged for debug purposes
|
310 |
+
*
|
311 |
+
* @see Net_SSH1::getServerKeyPublicModulus()
|
312 |
+
* @var String
|
313 |
+
* @access private
|
314 |
+
*/
|
315 |
+
var $server_key_public_modulus;
|
316 |
+
|
317 |
+
/**
|
318 |
+
* The Host Key Public Exponent
|
319 |
+
*
|
320 |
+
* Logged for debug purposes
|
321 |
+
*
|
322 |
+
* @see Net_SSH1::getHostKeyPublicExponent()
|
323 |
+
* @var String
|
324 |
+
* @access private
|
325 |
+
*/
|
326 |
+
var $host_key_public_exponent;
|
327 |
+
|
328 |
+
/**
|
329 |
+
* The Host Key Public Modulus
|
330 |
+
*
|
331 |
+
* Logged for debug purposes
|
332 |
+
*
|
333 |
+
* @see Net_SSH1::getHostKeyPublicModulus()
|
334 |
+
* @var String
|
335 |
+
* @access private
|
336 |
+
*/
|
337 |
+
var $host_key_public_modulus;
|
338 |
+
|
339 |
+
/**
|
340 |
+
* Supported Ciphers
|
341 |
+
*
|
342 |
+
* Logged for debug purposes
|
343 |
+
*
|
344 |
+
* @see Net_SSH1::getSupportedCiphers()
|
345 |
+
* @var Array
|
346 |
+
* @access private
|
347 |
+
*/
|
348 |
+
var $supported_ciphers = array(
|
349 |
+
NET_SSH1_CIPHER_NONE => 'No encryption',
|
350 |
+
NET_SSH1_CIPHER_IDEA => 'IDEA in CFB mode',
|
351 |
+
NET_SSH1_CIPHER_DES => 'DES in CBC mode',
|
352 |
+
NET_SSH1_CIPHER_3DES => 'Triple-DES in CBC mode',
|
353 |
+
NET_SSH1_CIPHER_BROKEN_TSS => 'TRI\'s Simple Stream encryption CBC',
|
354 |
+
NET_SSH1_CIPHER_RC4 => 'RC4',
|
355 |
+
NET_SSH1_CIPHER_BLOWFISH => 'Blowfish'
|
356 |
+
);
|
357 |
+
|
358 |
+
/**
|
359 |
+
* Supported Authentications
|
360 |
+
*
|
361 |
+
* Logged for debug purposes
|
362 |
+
*
|
363 |
+
* @see Net_SSH1::getSupportedAuthentications()
|
364 |
+
* @var Array
|
365 |
+
* @access private
|
366 |
+
*/
|
367 |
+
var $supported_authentications = array(
|
368 |
+
NET_SSH1_AUTH_RHOSTS => '.rhosts or /etc/hosts.equiv',
|
369 |
+
NET_SSH1_AUTH_RSA => 'pure RSA authentication',
|
370 |
+
NET_SSH1_AUTH_PASSWORD => 'password authentication',
|
371 |
+
NET_SSH1_AUTH_RHOSTS_RSA => '.rhosts with RSA host authentication'
|
372 |
+
);
|
373 |
+
|
374 |
+
/**
|
375 |
+
* Server Identification
|
376 |
+
*
|
377 |
+
* @see Net_SSH1::getServerIdentification()
|
378 |
+
* @var String
|
379 |
+
* @access private
|
380 |
+
*/
|
381 |
+
var $server_identification = '';
|
382 |
+
|
383 |
+
/**
|
384 |
+
* Protocol Flags
|
385 |
+
*
|
386 |
+
* @see Net_SSH1::Net_SSH1()
|
387 |
+
* @var Array
|
388 |
+
* @access private
|
389 |
+
*/
|
390 |
+
var $protocol_flags = array();
|
391 |
+
|
392 |
+
/**
|
393 |
+
* Protocol Flag Log
|
394 |
+
*
|
395 |
+
* @see Net_SSH1::getLog()
|
396 |
+
* @var Array
|
397 |
+
* @access private
|
398 |
+
*/
|
399 |
+
var $protocol_flag_log = array();
|
400 |
+
|
401 |
+
/**
|
402 |
+
* Message Log
|
403 |
+
*
|
404 |
+
* @see Net_SSH1::getLog()
|
405 |
+
* @var Array
|
406 |
+
* @access private
|
407 |
+
*/
|
408 |
+
var $message_log = array();
|
409 |
+
|
410 |
+
/**
|
411 |
+
* Interactive Buffer
|
412 |
+
*
|
413 |
+
* @see Net_SSH1::read()
|
414 |
+
* @var Array
|
415 |
+
* @access private
|
416 |
+
*/
|
417 |
+
var $interactive_buffer = '';
|
418 |
+
|
419 |
+
/**
|
420 |
+
* Default Constructor.
|
421 |
+
*
|
422 |
+
* Connects to an SSHv1 server
|
423 |
+
*
|
424 |
+
* @param String $host
|
425 |
+
* @param optional Integer $port
|
426 |
+
* @param optional Integer $timeout
|
427 |
+
* @param optional Integer $cipher
|
428 |
+
* @return Net_SSH1
|
429 |
+
* @access public
|
430 |
+
*/
|
431 |
+
function Net_SSH1($host, $port = 22, $timeout = 10, $cipher = NET_SSH1_CIPHER_3DES)
|
432 |
+
{
|
433 |
+
$this->protocol_flags = array(
|
434 |
+
1 => 'NET_SSH1_MSG_DISCONNECT',
|
435 |
+
2 => 'NET_SSH1_SMSG_PUBLIC_KEY',
|
436 |
+
3 => 'NET_SSH1_CMSG_SESSION_KEY',
|
437 |
+
4 => 'NET_SSH1_CMSG_USER',
|
438 |
+
9 => 'NET_SSH1_CMSG_AUTH_PASSWORD',
|
439 |
+
10 => 'NET_SSH1_CMSG_REQUEST_PTY',
|
440 |
+
12 => 'NET_SSH1_CMSG_EXEC_SHELL',
|
441 |
+
13 => 'NET_SSH1_CMSG_EXEC_CMD',
|
442 |
+
14 => 'NET_SSH1_SMSG_SUCCESS',
|
443 |
+
15 => 'NET_SSH1_SMSG_FAILURE',
|
444 |
+
16 => 'NET_SSH1_CMSG_STDIN_DATA',
|
445 |
+
17 => 'NET_SSH1_SMSG_STDOUT_DATA',
|
446 |
+
18 => 'NET_SSH1_SMSG_STDERR_DATA',
|
447 |
+
19 => 'NET_SSH1_CMSG_EOF',
|
448 |
+
20 => 'NET_SSH1_SMSG_EXITSTATUS',
|
449 |
+
33 => 'NET_SSH1_CMSG_EXIT_CONFIRMATION'
|
450 |
+
);
|
451 |
+
|
452 |
+
$this->_define_array($this->protocol_flags);
|
453 |
+
|
454 |
+
$this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
|
455 |
+
if (!$this->fsock) {
|
456 |
+
user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE);
|
457 |
+
return;
|
458 |
+
}
|
459 |
+
|
460 |
+
$this->server_identification = $init_line = fgets($this->fsock, 255);
|
461 |
+
|
462 |
+
if (defined('NET_SSH1_LOGGING')) {
|
463 |
+
$this->protocol_flags_log[] = '<-';
|
464 |
+
$this->protocol_flags_log[] = '->';
|
465 |
+
|
466 |
+
if (NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) {
|
467 |
+
$this->message_log[] = $this->server_identification;
|
468 |
+
$this->message_log[] = $this->identifier . "\r\n";
|
469 |
+
}
|
470 |
+
}
|
471 |
+
|
472 |
+
if (!preg_match('#SSH-([0-9\.]+)-(.+)#', $init_line, $parts)) {
|
473 |
+
user_error('Can only connect to SSH servers', E_USER_NOTICE);
|
474 |
+
return;
|
475 |
+
}
|
476 |
+
if ($parts[1][0] != 1) {
|
477 |
+
user_error("Cannot connect to SSH $parts[1] servers", E_USER_NOTICE);
|
478 |
+
return;
|
479 |
+
}
|
480 |
+
|
481 |
+
fputs($this->fsock, $this->identifier."\r\n");
|
482 |
+
|
483 |
+
$response = $this->_get_binary_packet();
|
484 |
+
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_PUBLIC_KEY) {
|
485 |
+
user_error('Expected SSH_SMSG_PUBLIC_KEY', E_USER_NOTICE);
|
486 |
+
return;
|
487 |
+
}
|
488 |
+
|
489 |
+
$anti_spoofing_cookie = $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 8);
|
490 |
+
|
491 |
+
$this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
|
492 |
+
|
493 |
+
$temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
|
494 |
+
$server_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
|
495 |
+
$this->server_key_public_exponent = $server_key_public_exponent;
|
496 |
+
|
497 |
+
$temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
|
498 |
+
$server_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
|
499 |
+
$this->server_key_public_modulus = $server_key_public_modulus;
|
500 |
+
|
501 |
+
$this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
|
502 |
+
|
503 |
+
$temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
|
504 |
+
$host_key_public_exponent = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
|
505 |
+
$this->host_key_public_exponent = $host_key_public_exponent;
|
506 |
+
|
507 |
+
$temp = unpack('nlen', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 2));
|
508 |
+
$host_key_public_modulus = new Math_BigInteger($this->_string_shift($response[NET_SSH1_RESPONSE_DATA], ceil($temp['len'] / 8)), 256);
|
509 |
+
$this->host_key_public_modulus = $host_key_public_modulus;
|
510 |
+
|
511 |
+
$this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4);
|
512 |
+
|
513 |
+
// get a list of the supported ciphers
|
514 |
+
extract(unpack('Nsupported_ciphers_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
|
515 |
+
foreach ($this->supported_ciphers as $mask=>$name) {
|
516 |
+
if (($supported_ciphers_mask & (1 << $mask)) == 0) {
|
517 |
+
unset($this->supported_ciphers[$mask]);
|
518 |
+
}
|
519 |
+
}
|
520 |
+
|
521 |
+
// get a list of the supported authentications
|
522 |
+
extract(unpack('Nsupported_authentications_mask', $this->_string_shift($response[NET_SSH1_RESPONSE_DATA], 4)));
|
523 |
+
foreach ($this->supported_authentications as $mask=>$name) {
|
524 |
+
if (($supported_authentications_mask & (1 << $mask)) == 0) {
|
525 |
+
unset($this->supported_authentications[$mask]);
|
526 |
+
}
|
527 |
+
}
|
528 |
+
|
529 |
+
$session_id = pack('H*', md5($host_key_public_modulus->toBytes() . $server_key_public_modulus->toBytes() . $anti_spoofing_cookie));
|
530 |
+
|
531 |
+
$session_key = '';
|
532 |
+
for ($i = 0; $i < 32; $i++) {
|
533 |
+
$session_key.= chr(crypt_random(0, 255));
|
534 |
+
}
|
535 |
+
$double_encrypted_session_key = $session_key ^ str_pad($session_id, 32, chr(0));
|
536 |
+
|
537 |
+
if ($server_key_public_modulus->compare($host_key_public_modulus) < 0) {
|
538 |
+
$double_encrypted_session_key = $this->_rsa_crypt(
|
539 |
+
$double_encrypted_session_key,
|
540 |
+
array(
|
541 |
+
$server_key_public_exponent,
|
542 |
+
$server_key_public_modulus
|
543 |
+
)
|
544 |
+
);
|
545 |
+
$double_encrypted_session_key = $this->_rsa_crypt(
|
546 |
+
$double_encrypted_session_key,
|
547 |
+
array(
|
548 |
+
$host_key_public_exponent,
|
549 |
+
$host_key_public_modulus
|
550 |
+
)
|
551 |
+
);
|
552 |
+
} else {
|
553 |
+
$double_encrypted_session_key = $this->_rsa_crypt(
|
554 |
+
$double_encrypted_session_key,
|
555 |
+
array(
|
556 |
+
$host_key_public_exponent,
|
557 |
+
$host_key_public_modulus
|
558 |
+
)
|
559 |
+
);
|
560 |
+
$double_encrypted_session_key = $this->_rsa_crypt(
|
561 |
+
$double_encrypted_session_key,
|
562 |
+
array(
|
563 |
+
$server_key_public_exponent,
|
564 |
+
$server_key_public_modulus
|
565 |
+
)
|
566 |
+
);
|
567 |
+
}
|
568 |
+
|
569 |
+
$cipher = isset($this->supported_ciphers[$cipher]) ? $cipher : NET_SSH1_CIPHER_3DES;
|
570 |
+
$data = pack('C2a*na*N', NET_SSH1_CMSG_SESSION_KEY, $cipher, $anti_spoofing_cookie, 8 * strlen($double_encrypted_session_key), $double_encrypted_session_key, 0);
|
571 |
+
|
572 |
+
if (!$this->_send_binary_packet($data)) {
|
573 |
+
user_error('Error sending SSH_CMSG_SESSION_KEY', E_USER_NOTICE);
|
574 |
+
return;
|
575 |
+
}
|
576 |
+
|
577 |
+
switch ($cipher) {
|
578 |
+
//case NET_SSH1_CIPHER_NONE:
|
579 |
+
// $this->crypto = new Crypt_Null();
|
580 |
+
// break;
|
581 |
+
case NET_SSH1_CIPHER_DES:
|
582 |
+
$this->crypto = new Crypt_DES();
|
583 |
+
$this->crypto->disablePadding();
|
584 |
+
$this->crypto->enableContinuousBuffer();
|
585 |
+
$this->crypto->setKey(substr($session_key, 0, 8));
|
586 |
+
break;
|
587 |
+
case NET_SSH1_CIPHER_3DES:
|
588 |
+
$this->crypto = new Crypt_TripleDES(CRYPT_DES_MODE_3CBC);
|
589 |
+
$this->crypto->disablePadding();
|
590 |
+
$this->crypto->enableContinuousBuffer();
|
591 |
+
$this->crypto->setKey(substr($session_key, 0, 24));
|
592 |
+
break;
|
593 |
+
//case NET_SSH1_CIPHER_RC4:
|
594 |
+
// $this->crypto = new Crypt_RC4();
|
595 |
+
// $this->crypto->enableContinuousBuffer();
|
596 |
+
// $this->crypto->setKey(substr($session_key, 0, 16));
|
597 |
+
// break;
|
598 |
+
}
|
599 |
+
|
600 |
+
$response = $this->_get_binary_packet();
|
601 |
+
|
602 |
+
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
|
603 |
+
user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE);
|
604 |
+
return;
|
605 |
+
}
|
606 |
+
|
607 |
+
$this->bitmap = NET_SSH1_MASK_CONSTRUCTOR;
|
608 |
+
}
|
609 |
+
|
610 |
+
/**
|
611 |
+
* Login
|
612 |
+
*
|
613 |
+
* @param String $username
|
614 |
+
* @param optional String $password
|
615 |
+
* @return Boolean
|
616 |
+
* @access public
|
617 |
+
*/
|
618 |
+
function login($username, $password = '')
|
619 |
+
{
|
620 |
+
if (!($this->bitmap & NET_SSH1_MASK_CONSTRUCTOR)) {
|
621 |
+
return false;
|
622 |
+
}
|
623 |
+
|
624 |
+
$data = pack('CNa*', NET_SSH1_CMSG_USER, strlen($username), $username);
|
625 |
+
|
626 |
+
if (!$this->_send_binary_packet($data)) {
|
627 |
+
user_error('Error sending SSH_CMSG_USER', E_USER_NOTICE);
|
628 |
+
return false;
|
629 |
+
}
|
630 |
+
|
631 |
+
$response = $this->_get_binary_packet();
|
632 |
+
|
633 |
+
if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
|
634 |
+
$this->bitmap |= NET_SSH1_MASK_LOGIN;
|
635 |
+
return true;
|
636 |
+
} else if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_FAILURE) {
|
637 |
+
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE', E_USER_NOTICE);
|
638 |
+
return false;
|
639 |
+
}
|
640 |
+
|
641 |
+
$data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen($password), $password);
|
642 |
+
|
643 |
+
if (!$this->_send_binary_packet($data)) {
|
644 |
+
user_error('Error sending SSH_CMSG_AUTH_PASSWORD', E_USER_NOTICE);
|
645 |
+
return false;
|
646 |
+
}
|
647 |
+
|
648 |
+
// remove the username and password from the last logged packet
|
649 |
+
if (defined('NET_SSH1_LOGGING') && NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) {
|
650 |
+
$data = pack('CNa*', NET_SSH1_CMSG_AUTH_PASSWORD, strlen('password'), 'password');
|
651 |
+
$this->message_log[count($this->message_log) - 1] = $data; // zzzzz
|
652 |
+
}
|
653 |
+
|
654 |
+
$response = $this->_get_binary_packet();
|
655 |
+
|
656 |
+
if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_SUCCESS) {
|
657 |
+
$this->bitmap |= NET_SSH1_MASK_LOGIN;
|
658 |
+
return true;
|
659 |
+
} else if ($response[NET_SSH1_RESPONSE_TYPE] == NET_SSH1_SMSG_FAILURE) {
|
660 |
+
return false;
|
661 |
+
} else {
|
662 |
+
user_error('Expected SSH_SMSG_SUCCESS or SSH_SMSG_FAILURE', E_USER_NOTICE);
|
663 |
+
return false;
|
664 |
+
}
|
665 |
+
}
|
666 |
+
|
667 |
+
/**
|
668 |
+
* Executes a command on a non-interactive shell, returns the output, and quits.
|
669 |
+
*
|
670 |
+
* An SSH1 server will close the connection after a command has been executed on a non-interactive shell. SSH2
|
671 |
+
* servers don't, however, this isn't an SSH2 client. The way this works, on the server, is by initiating a
|
672 |
+
* shell with the -s option, as discussed in the following links:
|
673 |
+
*
|
674 |
+
* {@link http://www.faqs.org/docs/bashman/bashref_65.html http://www.faqs.org/docs/bashman/bashref_65.html}
|
675 |
+
* {@link http://www.faqs.org/docs/bashman/bashref_62.html http://www.faqs.org/docs/bashman/bashref_62.html}
|
676 |
+
*
|
677 |
+
* To execute further commands, a new Net_SSH1 object will need to be created.
|
678 |
+
*
|
679 |
+
* Returns false on failure and the output, otherwise.
|
680 |
+
*
|
681 |
+
* @see Net_SSH1::interactiveRead()
|
682 |
+
* @see Net_SSH1::interactiveWrite()
|
683 |
+
* @param String $cmd
|
684 |
+
* @return mixed
|
685 |
+
* @access public
|
686 |
+
*/
|
687 |
+
function exec($cmd, $block = true)
|
688 |
+
{
|
689 |
+
if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
|
690 |
+
user_error('Operation disallowed prior to login()', E_USER_NOTICE);
|
691 |
+
return false;
|
692 |
+
}
|
693 |
+
|
694 |
+
$data = pack('CNa*', NET_SSH1_CMSG_EXEC_CMD, strlen($cmd), $cmd);
|
695 |
+
|
696 |
+
if (!$this->_send_binary_packet($data)) {
|
697 |
+
user_error('Error sending SSH_CMSG_EXEC_CMD', E_USER_NOTICE);
|
698 |
+
return false;
|
699 |
+
}
|
700 |
+
|
701 |
+
if (!$block) {
|
702 |
+
return true;
|
703 |
+
}
|
704 |
+
|
705 |
+
$output = '';
|
706 |
+
$response = $this->_get_binary_packet();
|
707 |
+
|
708 |
+
do {
|
709 |
+
$output.= substr($response[NET_SSH1_RESPONSE_DATA], 4);
|
710 |
+
$response = $this->_get_binary_packet();
|
711 |
+
} while ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_EXITSTATUS);
|
712 |
+
|
713 |
+
$data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
|
714 |
+
|
715 |
+
// i don't think it's really all that important if this packet gets sent or not.
|
716 |
+
$this->_send_binary_packet($data);
|
717 |
+
|
718 |
+
fclose($this->fsock);
|
719 |
+
|
720 |
+
// reset the execution bitmap - a new Net_SSH1 object needs to be created.
|
721 |
+
$this->bitmap = 0;
|
722 |
+
|
723 |
+
return $output;
|
724 |
+
}
|
725 |
+
|
726 |
+
/**
|
727 |
+
* Creates an interactive shell
|
728 |
+
*
|
729 |
+
* @see Net_SSH1::interactiveRead()
|
730 |
+
* @see Net_SSH1::interactiveWrite()
|
731 |
+
* @return Boolean
|
732 |
+
* @access private
|
733 |
+
*/
|
734 |
+
function _initShell()
|
735 |
+
{
|
736 |
+
// connect using the sample parameters in protocol-1.5.txt.
|
737 |
+
// according to wikipedia.org's entry on text terminals, "the fundamental type of application running on a text
|
738 |
+
// terminal is a command line interpreter or shell". thus, opening a terminal session to run the shell.
|
739 |
+
$data = pack('CNa*N4C', NET_SSH1_CMSG_REQUEST_PTY, strlen('vt100'), 'vt100', 24, 80, 0, 0, NET_SSH1_TTY_OP_END);
|
740 |
+
|
741 |
+
if (!$this->_send_binary_packet($data)) {
|
742 |
+
user_error('Error sending SSH_CMSG_REQUEST_PTY', E_USER_NOTICE);
|
743 |
+
return false;
|
744 |
+
}
|
745 |
+
|
746 |
+
$response = $this->_get_binary_packet();
|
747 |
+
|
748 |
+
if ($response[NET_SSH1_RESPONSE_TYPE] != NET_SSH1_SMSG_SUCCESS) {
|
749 |
+
user_error('Expected SSH_SMSG_SUCCESS', E_USER_NOTICE);
|
750 |
+
return false;
|
751 |
+
}
|
752 |
+
|
753 |
+
$data = pack('C', NET_SSH1_CMSG_EXEC_SHELL);
|
754 |
+
|
755 |
+
if (!$this->_send_binary_packet($data)) {
|
756 |
+
user_error('Error sending SSH_CMSG_EXEC_SHELL', E_USER_NOTICE);
|
757 |
+
return false;
|
758 |
+
}
|
759 |
+
|
760 |
+
$this->bitmap |= NET_SSH1_MASK_SHELL;
|
761 |
+
|
762 |
+
//stream_set_blocking($this->fsock, 0);
|
763 |
+
|
764 |
+
return true;
|
765 |
+
}
|
766 |
+
|
767 |
+
/**
|
768 |
+
* Inputs a command into an interactive shell.
|
769 |
+
*
|
770 |
+
* @see Net_SSH1::interactiveWrite()
|
771 |
+
* @param String $cmd
|
772 |
+
* @return Boolean
|
773 |
+
* @access public
|
774 |
+
*/
|
775 |
+
function write($cmd)
|
776 |
+
{
|
777 |
+
return $this->interactiveWrite($cmd);
|
778 |
+
}
|
779 |
+
|
780 |
+
/**
|
781 |
+
* Returns the output of an interactive shell when there's a match for $expect
|
782 |
+
*
|
783 |
+
* $expect can take the form of a string literal or, if $mode == NET_SSH1_READ_REGEX,
|
784 |
+
* a regular expression.
|
785 |
+
*
|
786 |
+
* @see Net_SSH1::write()
|
787 |
+
* @param String $expect
|
788 |
+
* @param Integer $mode
|
789 |
+
* @return Boolean
|
790 |
+
* @access public
|
791 |
+
*/
|
792 |
+
function read($expect, $mode = NET_SSH1_READ_SIMPLE)
|
793 |
+
{
|
794 |
+
if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
|
795 |
+
user_error('Operation disallowed prior to login()', E_USER_NOTICE);
|
796 |
+
return false;
|
797 |
+
}
|
798 |
+
|
799 |
+
if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
|
800 |
+
user_error('Unable to initiate an interactive shell session', E_USER_NOTICE);
|
801 |
+
return false;
|
802 |
+
}
|
803 |
+
|
804 |
+
$match = $expect;
|
805 |
+
while (true) {
|
806 |
+
if ($mode == NET_SSH1_READ_REGEX) {
|
807 |
+
preg_match($expect, $this->interactiveBuffer, $matches);
|
808 |
+
$match = $matches[0];
|
809 |
+
}
|
810 |
+
$pos = strpos($this->interactiveBuffer, $match);
|
811 |
+
if ($pos !== false) {
|
812 |
+
return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
|
813 |
+
}
|
814 |
+
$response = $this->_get_binary_packet();
|
815 |
+
$this->interactiveBuffer.= substr($response[NET_SSH1_RESPONSE_DATA], 4);
|
816 |
+
}
|
817 |
+
}
|
818 |
+
|
819 |
+
/**
|
820 |
+
* Inputs a command into an interactive shell.
|
821 |
+
*
|
822 |
+
* @see Net_SSH1::interactiveRead()
|
823 |
+
* @param String $cmd
|
824 |
+
* @return Boolean
|
825 |
+
* @access public
|
826 |
+
*/
|
827 |
+
function interactiveWrite($cmd)
|
828 |
+
{
|
829 |
+
if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
|
830 |
+
user_error('Operation disallowed prior to login()', E_USER_NOTICE);
|
831 |
+
return false;
|
832 |
+
}
|
833 |
+
|
834 |
+
if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
|
835 |
+
user_error('Unable to initiate an interactive shell session', E_USER_NOTICE);
|
836 |
+
return false;
|
837 |
+
}
|
838 |
+
|
839 |
+
$data = pack('CNa*', NET_SSH1_CMSG_STDIN_DATA, strlen($cmd), $cmd);
|
840 |
+
|
841 |
+
if (!$this->_send_binary_packet($data)) {
|
842 |
+
user_error('Error sending SSH_CMSG_STDIN', E_USER_NOTICE);
|
843 |
+
return false;
|
844 |
+
}
|
845 |
+
|
846 |
+
return true;
|
847 |
+
}
|
848 |
+
|
849 |
+
/**
|
850 |
+
* Returns the output of an interactive shell when no more output is available.
|
851 |
+
*
|
852 |
+
* Requires PHP 4.3.0 or later due to the use of the stream_select() function. If you see stuff like
|
853 |
+
* "[00m", you're seeing ANSI escape codes. According to
|
854 |
+
* {@link http://support.microsoft.com/kb/101875 How to Enable ANSI.SYS in a Command Window}, "Windows NT
|
855 |
+
* does not support ANSI escape sequences in Win32 Console applications", so if you're a Windows user,
|
856 |
+
* there's not going to be much recourse.
|
857 |
+
*
|
858 |
+
* @see Net_SSH1::interactiveRead()
|
859 |
+
* @return String
|
860 |
+
* @access public
|
861 |
+
*/
|
862 |
+
function interactiveRead()
|
863 |
+
{
|
864 |
+
if (!($this->bitmap & NET_SSH1_MASK_LOGIN)) {
|
865 |
+
user_error('Operation disallowed prior to login()', E_USER_NOTICE);
|
866 |
+
return false;
|
867 |
+
}
|
868 |
+
|
869 |
+
if (!($this->bitmap & NET_SSH1_MASK_SHELL) && !$this->_initShell()) {
|
870 |
+
user_error('Unable to initiate an interactive shell session', E_USER_NOTICE);
|
871 |
+
return false;
|
872 |
+
}
|
873 |
+
|
874 |
+
$read = array($this->fsock);
|
875 |
+
$write = $except = null;
|
876 |
+
if (stream_select($read, $write, $except, 0)) {
|
877 |
+
$response = $this->_get_binary_packet();
|
878 |
+
return substr($response[NET_SSH1_RESPONSE_DATA], 4);
|
879 |
+
} else {
|
880 |
+
return '';
|
881 |
+
}
|
882 |
+
}
|
883 |
+
|
884 |
+
/**
|
885 |
+
* Disconnect
|
886 |
+
*
|
887 |
+
* @access public
|
888 |
+
*/
|
889 |
+
function disconnect()
|
890 |
+
{
|
891 |
+
$this->_disconnect();
|
892 |
+
}
|
893 |
+
|
894 |
+
/**
|
895 |
+
* Destructor.
|
896 |
+
*
|
897 |
+
* Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
|
898 |
+
* disconnect().
|
899 |
+
*
|
900 |
+
* @access public
|
901 |
+
*/
|
902 |
+
function __destruct()
|
903 |
+
{
|
904 |
+
$this->_disconnect();
|
905 |
+
}
|
906 |
+
|
907 |
+
/**
|
908 |
+
* Disconnect
|
909 |
+
*
|
910 |
+
* @param String $msg
|
911 |
+
* @access private
|
912 |
+
*/
|
913 |
+
function _disconnect($msg = 'Client Quit')
|
914 |
+
{
|
915 |
+
if ($this->bitmap) {
|
916 |
+
$data = pack('C', NET_SSH1_CMSG_EOF);
|
917 |
+
$this->_send_binary_packet($data);
|
918 |
+
|
919 |
+
$response = $this->_get_binary_packet();
|
920 |
+
switch ($response[NET_SSH1_RESPONSE_TYPE]) {
|
921 |
+
case NET_SSH1_SMSG_EXITSTATUS:
|
922 |
+
$data = pack('C', NET_SSH1_CMSG_EXIT_CONFIRMATION);
|
923 |
+
break;
|
924 |
+
default:
|
925 |
+
$data = pack('CNa*', NET_SSH1_MSG_DISCONNECT, strlen($msg), $msg);
|
926 |
+
}
|
927 |
+
|
928 |
+
$this->_send_binary_packet($data);
|
929 |
+
fclose($this->fsock);
|
930 |
+
$this->bitmap = 0;
|
931 |
+
}
|
932 |
+
}
|
933 |
+
|
934 |
+
/**
|
935 |
+
* Gets Binary Packets
|
936 |
+
*
|
937 |
+
* See 'The Binary Packet Protocol' of protocol-1.5.txt for more info.
|
938 |
+
*
|
939 |
+
* Also, this function could be improved upon by adding detection for the following exploit:
|
940 |
+
* http://www.securiteam.com/securitynews/5LP042K3FY.html
|
941 |
+
*
|
942 |
+
* @see Net_SSH1::_send_binary_packet()
|
943 |
+
* @return Array
|
944 |
+
* @access private
|
945 |
+
*/
|
946 |
+
function _get_binary_packet()
|
947 |
+
{
|
948 |
+
if (feof($this->fsock)) {
|
949 |
+
//user_error('connection closed prematurely', E_USER_NOTICE);
|
950 |
+
return false;
|
951 |
+
}
|
952 |
+
|
953 |
+
$temp = unpack('Nlength', fread($this->fsock, 4));
|
954 |
+
|
955 |
+
$padding_length = 8 - ($temp['length'] & 7);
|
956 |
+
$length = $temp['length'] + $padding_length;
|
957 |
+
|
958 |
+
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
|
959 |
+
$raw = fread($this->fsock, $length);
|
960 |
+
$stop = strtok(microtime(), ' ') + strtok('');
|
961 |
+
|
962 |
+
if ($this->crypto !== false) {
|
963 |
+
$raw = $this->crypto->decrypt($raw);
|
964 |
+
}
|
965 |
+
|
966 |
+
$padding = substr($raw, 0, $padding_length);
|
967 |
+
$type = $raw[$padding_length];
|
968 |
+
$data = substr($raw, $padding_length + 1, -4);
|
969 |
+
|
970 |
+
$temp = unpack('Ncrc', substr($raw, -4));
|
971 |
+
|
972 |
+
//if ( $temp['crc'] != $this->_crc($padding . $type . $data) ) {
|
973 |
+
// user_error('Bad CRC in packet from server', E_USER_NOTICE);
|
974 |
+
// return false;
|
975 |
+
//}
|
976 |
+
|
977 |
+
$type = ord($type);
|
978 |
+
|
979 |
+
if (defined('NET_SSH1_LOGGING')) {
|
980 |
+
$temp = isset($this->protocol_flags[$type]) ? $this->protocol_flags[$type] : 'UNKNOWN';
|
981 |
+
$this->protocol_flags_log[] = '<- ' . $temp .
|
982 |
+
' (' . round($stop - $start, 4) . 's)';
|
983 |
+
if (NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) {
|
984 |
+
$this->message_log[] = $data;
|
985 |
+
}
|
986 |
+
}
|
987 |
+
|
988 |
+
return array(
|
989 |
+
NET_SSH1_RESPONSE_TYPE => $type,
|
990 |
+
NET_SSH1_RESPONSE_DATA => $data
|
991 |
+
);
|
992 |
+
}
|
993 |
+
|
994 |
+
/**
|
995 |
+
* Sends Binary Packets
|
996 |
+
*
|
997 |
+
* Returns true on success, false on failure.
|
998 |
+
*
|
999 |
+
* @see Net_SSH1::_get_binary_packet()
|
1000 |
+
* @param String $data
|
1001 |
+
* @return Boolean
|
1002 |
+
* @access private
|
1003 |
+
*/
|
1004 |
+
function _send_binary_packet($data) {
|
1005 |
+
if (feof($this->fsock)) {
|
1006 |
+
//user_error('connection closed prematurely', E_USER_NOTICE);
|
1007 |
+
return false;
|
1008 |
+
}
|
1009 |
+
|
1010 |
+
if (defined('NET_SSH1_LOGGING')) {
|
1011 |
+
$temp = isset($this->protocol_flags[ord($data[0])]) ? $this->protocol_flags[ord($data[0])] : 'UNKNOWN';
|
1012 |
+
$this->protocol_flags_log[] = '-> ' . $temp .
|
1013 |
+
' (' . round($stop - $start, 4) . 's)';
|
1014 |
+
if (NET_SSH1_LOGGING == NET_SSH1_LOG_COMPLEX) {
|
1015 |
+
$this->message_log[] = substr($data, 1);
|
1016 |
+
}
|
1017 |
+
}
|
1018 |
+
|
1019 |
+
$length = strlen($data) + 4;
|
1020 |
+
|
1021 |
+
$padding_length = 8 - ($length & 7);
|
1022 |
+
$padding = '';
|
1023 |
+
for ($i = 0; $i < $padding_length; $i++) {
|
1024 |
+
$padding.= chr(crypt_random(0, 255));
|
1025 |
+
}
|
1026 |
+
|
1027 |
+
$data = $padding . $data;
|
1028 |
+
$data.= pack('N', $this->_crc($data));
|
1029 |
+
|
1030 |
+
if ($this->crypto !== false) {
|
1031 |
+
$data = $this->crypto->encrypt($data);
|
1032 |
+
}
|
1033 |
+
|
1034 |
+
$packet = pack('Na*', $length, $data);
|
1035 |
+
|
1036 |
+
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
|
1037 |
+
$result = strlen($packet) == fputs($this->fsock, $packet);
|
1038 |
+
$stop = strtok(microtime(), ' ') + strtok('');
|
1039 |
+
|
1040 |
+
return $result;
|
1041 |
+
}
|
1042 |
+
|
1043 |
+
/**
|
1044 |
+
* Cyclic Redundancy Check (CRC)
|
1045 |
+
*
|
1046 |
+
* PHP's crc32 function is implemented slightly differently than the one that SSH v1 uses, so
|
1047 |
+
* we've reimplemented it. A more detailed discussion of the differences can be found after
|
1048 |
+
* $crc_lookup_table's initialization.
|
1049 |
+
*
|
1050 |
+
* @see Net_SSH1::_get_binary_packet()
|
1051 |
+
* @see Net_SSH1::_send_binary_packet()
|
1052 |
+
* @param String $data
|
1053 |
+
* @return Integer
|
1054 |
+
* @access private
|
1055 |
+
*/
|
1056 |
+
function _crc($data)
|
1057 |
+
{
|
1058 |
+
static $crc_lookup_table = array(
|
1059 |
+
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
|
1060 |
+
0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
|
1061 |
+
0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
|
1062 |
+
0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
|
1063 |
+
0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
|
1064 |
+
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
|
1065 |
+
0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
|
1066 |
+
0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
|
1067 |
+
0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
|
1068 |
+
0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
|
1069 |
+
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
|
1070 |
+
0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
|
1071 |
+
0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
|
1072 |
+
0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
|
1073 |
+
0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
|
1074 |
+
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,
|
1075 |
+
0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
|
1076 |
+
0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
|
1077 |
+
0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
|
1078 |
+
0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
|
1079 |
+
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
|
1080 |
+
0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
|
1081 |
+
0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
|
1082 |
+
0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
|
1083 |
+
0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
|
1084 |
+
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
|
1085 |
+
0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
|
1086 |
+
0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
|
1087 |
+
0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
|
1088 |
+
0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
|
1089 |
+
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
|
1090 |
+
0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,
|
1091 |
+
0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
|
1092 |
+
0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
|
1093 |
+
0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
|
1094 |
+
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
|
1095 |
+
0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
|
1096 |
+
0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
|
1097 |
+
0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
|
1098 |
+
0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
|
1099 |
+
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
|
1100 |
+
0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
|
1101 |
+
0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
|
1102 |
+
0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
|
1103 |
+
0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
|
1104 |
+
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
|
1105 |
+
0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
|
1106 |
+
0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,
|
1107 |
+
0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
|
1108 |
+
0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
|
1109 |
+
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
|
1110 |
+
0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
|
1111 |
+
0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
|
1112 |
+
0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
|
1113 |
+
0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
|
1114 |
+
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
|
1115 |
+
0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
|
1116 |
+
0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
|
1117 |
+
0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
|
1118 |
+
0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
|
1119 |
+
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
|
1120 |
+
0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
|
1121 |
+
0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
|
1122 |
+
0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
|
1123 |
+
);
|
1124 |
+
|
1125 |
+
// For this function to yield the same output as PHP's crc32 function, $crc would have to be
|
1126 |
+
// set to 0xFFFFFFFF, initially - not 0x00000000 as it currently is.
|
1127 |
+
$crc = 0x00000000;
|
1128 |
+
$length = strlen($data);
|
1129 |
+
|
1130 |
+
for ($i=0;$i<$length;$i++) {
|
1131 |
+
// We AND $crc >> 8 with 0x00FFFFFF because we want the eight newly added bits to all
|
1132 |
+
// be zero. PHP, unfortunately, doesn't always do this. 0x80000000 >> 8, as an example,
|
1133 |
+
// yields 0xFF800000 - not 0x00800000. The following link elaborates:
|
1134 |
+
// http://www.php.net/manual/en/language.operators.bitwise.php#57281
|
1135 |
+
$crc = (($crc >> 8) & 0x00FFFFFF) ^ $crc_lookup_table[($crc & 0xFF) ^ ord($data[$i])];
|
1136 |
+
}
|
1137 |
+
|
1138 |
+
// In addition to having to set $crc to 0xFFFFFFFF, initially, the return value must be XOR'd with
|
1139 |
+
// 0xFFFFFFFF for this function to return the same thing that PHP's crc32 function would.
|
1140 |
+
return $crc;
|
1141 |
+
}
|
1142 |
+
|
1143 |
+
/**
|
1144 |
+
* String Shift
|
1145 |
+
*
|
1146 |
+
* Inspired by array_shift
|
1147 |
+
*
|
1148 |
+
* @param String $string
|
1149 |
+
* @param optional Integer $index
|
1150 |
+
* @return String
|
1151 |
+
* @access private
|
1152 |
+
*/
|
1153 |
+
function _string_shift(&$string, $index = 1)
|
1154 |
+
{
|
1155 |
+
$substr = substr($string, 0, $index);
|
1156 |
+
$string = substr($string, $index);
|
1157 |
+
return $substr;
|
1158 |
+
}
|
1159 |
+
|
1160 |
+
/**
|
1161 |
+
* RSA Encrypt
|
1162 |
+
*
|
1163 |
+
* Returns mod(pow($m, $e), $n), where $n should be the product of two (large) primes $p and $q and where $e
|
1164 |
+
* should be a number with the property that gcd($e, ($p - 1) * ($q - 1)) == 1. Could just make anything that
|
1165 |
+
* calls this call modexp, instead, but I think this makes things clearer, maybe...
|
1166 |
+
*
|
1167 |
+
* @see Net_SSH1::Net_SSH1()
|
1168 |
+
* @param Math_BigInteger $m
|
1169 |
+
* @param Array $key
|
1170 |
+
* @return Math_BigInteger
|
1171 |
+
* @access private
|
1172 |
+
*/
|
1173 |
+
function _rsa_crypt($m, $key)
|
1174 |
+
{
|
1175 |
+
/*
|
1176 |
+
if (!class_exists('Crypt_RSA')) {
|
1177 |
+
require_once('Crypt/RSA.php');
|
1178 |
+
}
|
1179 |
+
|
1180 |
+
$rsa = new Crypt_RSA();
|
1181 |
+
$rsa->loadKey($key, CRYPT_RSA_PUBLIC_FORMAT_RAW);
|
1182 |
+
$rsa->setEncryptionMode(CRYPT_RSA_ENCRYPTION_PKCS1);
|
1183 |
+
return $rsa->encrypt($m);
|
1184 |
+
*/
|
1185 |
+
|
1186 |
+
// To quote from protocol-1.5.txt:
|
1187 |
+
// The most significant byte (which is only partial as the value must be
|
1188 |
+
// less than the public modulus, which is never a power of two) is zero.
|
1189 |
+
//
|
1190 |
+
// The next byte contains the value 2 (which stands for public-key
|
1191 |
+
// encrypted data in the PKCS standard [PKCS#1]). Then, there are non-
|
1192 |
+
// zero random bytes to fill any unused space, a zero byte, and the data
|
1193 |
+
// to be encrypted in the least significant bytes, the last byte of the
|
1194 |
+
// data in the least significant byte.
|
1195 |
+
|
1196 |
+
// Presumably the part of PKCS#1 they're refering to is "Section 7.2.1 Encryption Operation",
|
1197 |
+
// under "7.2 RSAES-PKCS1-v1.5" and "7 Encryption schemes" of the following URL:
|
1198 |
+
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
|
1199 |
+
$temp = chr(0) . chr(2);
|
1200 |
+
$modulus = $key[1]->toBytes();
|
1201 |
+
$length = strlen($modulus) - strlen($m) - 3;
|
1202 |
+
for ($i = 0; $i < $length; $i++) {
|
1203 |
+
$temp.= chr(crypt_random(1, 255));
|
1204 |
+
}
|
1205 |
+
$temp.= chr(0) . $m;
|
1206 |
+
|
1207 |
+
$m = new Math_BigInteger($temp, 256);
|
1208 |
+
$m = $m->modPow($key[0], $key[1]);
|
1209 |
+
|
1210 |
+
return $m->toBytes();
|
1211 |
+
}
|
1212 |
+
|
1213 |
+
/**
|
1214 |
+
* Define Array
|
1215 |
+
*
|
1216 |
+
* Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
|
1217 |
+
* named constants from it, using the value as the name of the constant and the index as the value of the constant.
|
1218 |
+
* If any of the constants that would be defined already exists, none of the constants will be defined.
|
1219 |
+
*
|
1220 |
+
* @param Array $array
|
1221 |
+
* @access private
|
1222 |
+
*/
|
1223 |
+
function _define_array()
|
1224 |
+
{
|
1225 |
+
$args = func_get_args();
|
1226 |
+
foreach ($args as $arg) {
|
1227 |
+
foreach ($arg as $key=>$value) {
|
1228 |
+
if (!defined($value)) {
|
1229 |
+
define($value, $key);
|
1230 |
+
} else {
|
1231 |
+
break 2;
|
1232 |
+
}
|
1233 |
+
}
|
1234 |
+
}
|
1235 |
+
}
|
1236 |
+
|
1237 |
+
/**
|
1238 |
+
* Returns a log of the packets that have been sent and received.
|
1239 |
+
*
|
1240 |
+
* Returns a string if NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX, an array if NET_SSH2_LOGGING == NET_SSH2_LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING')
|
1241 |
+
*
|
1242 |
+
* @access public
|
1243 |
+
* @return String or Array
|
1244 |
+
*/
|
1245 |
+
function getLog()
|
1246 |
+
{
|
1247 |
+
if (!defined('NET_SSH1_LOGGING')) {
|
1248 |
+
return false;
|
1249 |
+
}
|
1250 |
+
|
1251 |
+
switch (NET_SSH1_LOGGING) {
|
1252 |
+
case NET_SSH1_LOG_SIMPLE:
|
1253 |
+
return $this->message_number_log;
|
1254 |
+
break;
|
1255 |
+
case NET_SSH1_LOG_COMPLEX:
|
1256 |
+
return $this->_format_log($this->message_log, $this->protocol_flags_log);
|
1257 |
+
break;
|
1258 |
+
default:
|
1259 |
+
return false;
|
1260 |
+
}
|
1261 |
+
}
|
1262 |
+
|
1263 |
+
/**
|
1264 |
+
* Formats a log for printing
|
1265 |
+
*
|
1266 |
+
* @param Array $message_log
|
1267 |
+
* @param Array $message_number_log
|
1268 |
+
* @access private
|
1269 |
+
* @return String
|
1270 |
+
*/
|
1271 |
+
function _format_log($message_log, $message_number_log)
|
1272 |
+
{
|
1273 |
+
static $boundary = ':', $long_width = 65, $short_width = 16;
|
1274 |
+
|
1275 |
+
$output = '';
|
1276 |
+
for ($i = 0; $i < count($message_log); $i++) {
|
1277 |
+
$output.= $message_number_log[$i] . "\r\n";
|
1278 |
+
$current_log = $message_log[$i];
|
1279 |
+
$j = 0;
|
1280 |
+
do {
|
1281 |
+
if (!empty($current_log)) {
|
1282 |
+
$output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 ';
|
1283 |
+
}
|
1284 |
+
$fragment = $this->_string_shift($current_log, $short_width);
|
1285 |
+
$hex = substr(
|
1286 |
+
preg_replace(
|
1287 |
+
'#(.)#es',
|
1288 |
+
'"' . $boundary . '" . str_pad(dechex(ord(substr("\\1", -1))), 2, "0", STR_PAD_LEFT)',
|
1289 |
+
$fragment),
|
1290 |
+
strlen($boundary)
|
1291 |
+
);
|
1292 |
+
// replace non ASCII printable characters with dots
|
1293 |
+
// http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
|
1294 |
+
// also replace < with a . since < messes up the output on web browsers
|
1295 |
+
$raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
|
1296 |
+
$output.= str_pad($hex, $long_width - $short_width, ' ') . $raw . "\r\n";
|
1297 |
+
$j++;
|
1298 |
+
} while (!empty($current_log));
|
1299 |
+
$output.= "\r\n";
|
1300 |
+
}
|
1301 |
+
|
1302 |
+
return $output;
|
1303 |
+
}
|
1304 |
+
|
1305 |
+
/**
|
1306 |
+
* Return the server key public exponent
|
1307 |
+
*
|
1308 |
+
* Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
|
1309 |
+
* the raw bytes. This behavior is similar to PHP's md5() function.
|
1310 |
+
*
|
1311 |
+
* @param optional Boolean $raw_output
|
1312 |
+
* @return String
|
1313 |
+
* @access public
|
1314 |
+
*/
|
1315 |
+
function getServerKeyPublicExponent($raw_output = false)
|
1316 |
+
{
|
1317 |
+
return $raw_output ? $this->server_key_public_exponent->toBytes() : $this->server_key_public_exponent->toString();
|
1318 |
+
}
|
1319 |
+
|
1320 |
+
/**
|
1321 |
+
* Return the server key public modulus
|
1322 |
+
*
|
1323 |
+
* Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
|
1324 |
+
* the raw bytes. This behavior is similar to PHP's md5() function.
|
1325 |
+
*
|
1326 |
+
* @param optional Boolean $raw_output
|
1327 |
+
* @return String
|
1328 |
+
* @access public
|
1329 |
+
*/
|
1330 |
+
function getServerKeyPublicModulus($raw_output = false)
|
1331 |
+
{
|
1332 |
+
return $raw_output ? $this->server_key_public_modulus->toBytes() : $this->server_key_public_modulus->toString();
|
1333 |
+
}
|
1334 |
+
|
1335 |
+
/**
|
1336 |
+
* Return the host key public exponent
|
1337 |
+
*
|
1338 |
+
* Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
|
1339 |
+
* the raw bytes. This behavior is similar to PHP's md5() function.
|
1340 |
+
*
|
1341 |
+
* @param optional Boolean $raw_output
|
1342 |
+
* @return String
|
1343 |
+
* @access public
|
1344 |
+
*/
|
1345 |
+
function getHostKeyPublicExponent($raw_output = false)
|
1346 |
+
{
|
1347 |
+
return $raw_output ? $this->host_key_public_exponent->toBytes() : $this->host_key_public_exponent->toString();
|
1348 |
+
}
|
1349 |
+
|
1350 |
+
/**
|
1351 |
+
* Return the host key public modulus
|
1352 |
+
*
|
1353 |
+
* Returns, by default, the base-10 representation. If $raw_output is set to true, returns, instead,
|
1354 |
+
* the raw bytes. This behavior is similar to PHP's md5() function.
|
1355 |
+
*
|
1356 |
+
* @param optional Boolean $raw_output
|
1357 |
+
* @return String
|
1358 |
+
* @access public
|
1359 |
+
*/
|
1360 |
+
function getHostKeyPublicModulus($raw_output = false)
|
1361 |
+
{
|
1362 |
+
return $raw_output ? $this->host_key_public_modulus->toBytes() : $this->host_key_public_modulus->toString();
|
1363 |
+
}
|
1364 |
+
|
1365 |
+
/**
|
1366 |
+
* Return a list of ciphers supported by SSH1 server.
|
1367 |
+
*
|
1368 |
+
* Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
|
1369 |
+
* is set to true, returns, instead, an array of constants. ie. instead of array('Triple-DES in CBC mode'), you'll
|
1370 |
+
* get array(NET_SSH1_CIPHER_3DES).
|
1371 |
+
*
|
1372 |
+
* @param optional Boolean $raw_output
|
1373 |
+
* @return Array
|
1374 |
+
* @access public
|
1375 |
+
*/
|
1376 |
+
function getSupportedCiphers($raw_output = false)
|
1377 |
+
{
|
1378 |
+
return $raw_output ? array_keys($this->supported_ciphers) : array_values($this->supported_ciphers);
|
1379 |
+
}
|
1380 |
+
|
1381 |
+
/**
|
1382 |
+
* Return a list of authentications supported by SSH1 server.
|
1383 |
+
*
|
1384 |
+
* Just because a cipher is supported by an SSH1 server doesn't mean it's supported by this library. If $raw_output
|
1385 |
+
* is set to true, returns, instead, an array of constants. ie. instead of array('password authentication'), you'll
|
1386 |
+
* get array(NET_SSH1_AUTH_PASSWORD).
|
1387 |
+
*
|
1388 |
+
* @param optional Boolean $raw_output
|
1389 |
+
* @return Array
|
1390 |
+
* @access public
|
1391 |
+
*/
|
1392 |
+
function getSupportedAuthentications($raw_output = false)
|
1393 |
+
{
|
1394 |
+
return $raw_output ? array_keys($this->supported_authentications) : array_values($this->supported_authentications);
|
1395 |
+
}
|
1396 |
+
|
1397 |
+
/**
|
1398 |
+
* Return the server identification.
|
1399 |
+
*
|
1400 |
+
* @return String
|
1401 |
+
* @access public
|
1402 |
+
*/
|
1403 |
+
function getServerIdentification()
|
1404 |
+
{
|
1405 |
+
return rtrim($this->server_identification);
|
1406 |
+
}
|
1407 |
+
}
|
1408 |
+
?>
|
classes/phpseclib/Net/SSH2.php
ADDED
@@ -0,0 +1,2660 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */
|
3 |
+
|
4 |
+
/**
|
5 |
+
* Pure-PHP implementation of SSHv2.
|
6 |
+
*
|
7 |
+
* PHP versions 4 and 5
|
8 |
+
*
|
9 |
+
* Here are some examples of how to use this library:
|
10 |
+
* <code>
|
11 |
+
* <?php
|
12 |
+
* include('Net/SSH2.php');
|
13 |
+
*
|
14 |
+
* $ssh = new Net_SSH2('www.domain.tld');
|
15 |
+
* if (!$ssh->login('username', 'password')) {
|
16 |
+
* exit('Login Failed');
|
17 |
+
* }
|
18 |
+
*
|
19 |
+
* echo $ssh->exec('pwd');
|
20 |
+
* echo $ssh->exec('ls -la');
|
21 |
+
* ?>
|
22 |
+
* </code>
|
23 |
+
*
|
24 |
+
* <code>
|
25 |
+
* <?php
|
26 |
+
* include('Crypt/RSA.php');
|
27 |
+
* include('Net/SSH2.php');
|
28 |
+
*
|
29 |
+
* $key = new Crypt_RSA();
|
30 |
+
* //$key->setPassword('whatever');
|
31 |
+
* $key->loadKey(file_get_contents('privatekey'));
|
32 |
+
*
|
33 |
+
* $ssh = new Net_SSH2('www.domain.tld');
|
34 |
+
* if (!$ssh->login('username', $key)) {
|
35 |
+
* exit('Login Failed');
|
36 |
+
* }
|
37 |
+
*
|
38 |
+
* echo $ssh->read('username@username:~$');
|
39 |
+
* $ssh->write("ls -la\n");
|
40 |
+
* echo $ssh->read('username@username:~$');
|
41 |
+
* ?>
|
42 |
+
* </code>
|
43 |
+
*
|
44 |
+
* LICENSE: Permission is hereby granted, free of charge, to any person obtaining a copy
|
45 |
+
* of this software and associated documentation files (the "Software"), to deal
|
46 |
+
* in the Software without restriction, including without limitation the rights
|
47 |
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
48 |
+
* copies of the Software, and to permit persons to whom the Software is
|
49 |
+
* furnished to do so, subject to the following conditions:
|
50 |
+
*
|
51 |
+
* The above copyright notice and this permission notice shall be included in
|
52 |
+
* all copies or substantial portions of the Software.
|
53 |
+
*
|
54 |
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
55 |
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
56 |
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
57 |
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
58 |
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
59 |
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
60 |
+
* THE SOFTWARE.
|
61 |
+
*
|
62 |
+
* @category Net
|
63 |
+
* @package Net_SSH2
|
64 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
65 |
+
* @copyright MMVII Jim Wigginton
|
66 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
67 |
+
* @version $Id: SSH2.php,v 1.53 2010-10-24 01:24:30 terrafrost Exp $
|
68 |
+
* @link http://phpseclib.sourceforge.net
|
69 |
+
*/
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Include Math_BigInteger
|
73 |
+
*
|
74 |
+
* Used to do Diffie-Hellman key exchange and DSA/RSA signature verification.
|
75 |
+
*/
|
76 |
+
require_once('Math/BigInteger.php');
|
77 |
+
|
78 |
+
/**
|
79 |
+
* Include Crypt_Random
|
80 |
+
*/
|
81 |
+
require_once('Crypt/Random.php');
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Include Crypt_Hash
|
85 |
+
*/
|
86 |
+
require_once('Crypt/Hash.php');
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Include Crypt_TripleDES
|
90 |
+
*/
|
91 |
+
require_once('Crypt/TripleDES.php');
|
92 |
+
|
93 |
+
/**
|
94 |
+
* Include Crypt_RC4
|
95 |
+
*/
|
96 |
+
require_once('Crypt/RC4.php');
|
97 |
+
|
98 |
+
/**
|
99 |
+
* Include Crypt_AES
|
100 |
+
*/
|
101 |
+
require_once('Crypt/AES.php');
|
102 |
+
|
103 |
+
/**#@+
|
104 |
+
* Execution Bitmap Masks
|
105 |
+
*
|
106 |
+
* @see Net_SSH2::bitmap
|
107 |
+
* @access private
|
108 |
+
*/
|
109 |
+
define('NET_SSH2_MASK_CONSTRUCTOR', 0x00000001);
|
110 |
+
define('NET_SSH2_MASK_LOGIN', 0x00000002);
|
111 |
+
define('NET_SSH2_MASK_SHELL', 0x00000004);
|
112 |
+
/**#@-*/
|
113 |
+
|
114 |
+
/**#@+
|
115 |
+
* Channel constants
|
116 |
+
*
|
117 |
+
* RFC4254 refers not to client and server channels but rather to sender and recipient channels. we don't refer
|
118 |
+
* to them in that way because RFC4254 toggles the meaning. the client sends a SSH_MSG_CHANNEL_OPEN message with
|
119 |
+
* a sender channel and the server sends a SSH_MSG_CHANNEL_OPEN_CONFIRMATION in response, with a sender and a
|
120 |
+
* recepient channel. at first glance, you might conclude that SSH_MSG_CHANNEL_OPEN_CONFIRMATION's sender channel
|
121 |
+
* would be the same thing as SSH_MSG_CHANNEL_OPEN's sender channel, but it's not, per this snipet:
|
122 |
+
* The 'recipient channel' is the channel number given in the original
|
123 |
+
* open request, and 'sender channel' is the channel number allocated by
|
124 |
+
* the other side.
|
125 |
+
*
|
126 |
+
* @see Net_SSH2::_send_channel_packet()
|
127 |
+
* @see Net_SSH2::_get_channel_packet()
|
128 |
+
* @access private
|
129 |
+
*/
|
130 |
+
define('NET_SSH2_CHANNEL_EXEC', 0); // PuTTy uses 0x100
|
131 |
+
define('NET_SSH2_CHANNEL_SHELL',1);
|
132 |
+
/**#@-*/
|
133 |
+
|
134 |
+
/**#@+
|
135 |
+
* @access public
|
136 |
+
* @see Net_SSH2::getLog()
|
137 |
+
*/
|
138 |
+
/**
|
139 |
+
* Returns the message numbers
|
140 |
+
*/
|
141 |
+
define('NET_SSH2_LOG_SIMPLE', 1);
|
142 |
+
/**
|
143 |
+
* Returns the message content
|
144 |
+
*/
|
145 |
+
define('NET_SSH2_LOG_COMPLEX', 2);
|
146 |
+
/**#@-*/
|
147 |
+
|
148 |
+
/**#@+
|
149 |
+
* @access public
|
150 |
+
* @see Net_SSH2::read()
|
151 |
+
*/
|
152 |
+
/**
|
153 |
+
* Returns when a string matching $expect exactly is found
|
154 |
+
*/
|
155 |
+
define('NET_SSH2_READ_SIMPLE', 1);
|
156 |
+
/**
|
157 |
+
* Returns when a string matching the regular expression $expect is found
|
158 |
+
*/
|
159 |
+
define('NET_SSH2_READ_REGEX', 2);
|
160 |
+
/**#@-*/
|
161 |
+
|
162 |
+
/**
|
163 |
+
* Pure-PHP implementation of SSHv2.
|
164 |
+
*
|
165 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
166 |
+
* @version 0.1.0
|
167 |
+
* @access public
|
168 |
+
* @package Net_SSH2
|
169 |
+
*/
|
170 |
+
class Net_SSH2 {
|
171 |
+
/**
|
172 |
+
* The SSH identifier
|
173 |
+
*
|
174 |
+
* @var String
|
175 |
+
* @access private
|
176 |
+
*/
|
177 |
+
var $identifier = 'SSH-2.0-phpseclib_0.2';
|
178 |
+
|
179 |
+
/**
|
180 |
+
* The Socket Object
|
181 |
+
*
|
182 |
+
* @var Object
|
183 |
+
* @access private
|
184 |
+
*/
|
185 |
+
var $fsock;
|
186 |
+
|
187 |
+
/**
|
188 |
+
* Execution Bitmap
|
189 |
+
*
|
190 |
+
* The bits that are set reprsent functions that have been called already. This is used to determine
|
191 |
+
* if a requisite function has been successfully executed. If not, an error should be thrown.
|
192 |
+
*
|
193 |
+
* @var Integer
|
194 |
+
* @access private
|
195 |
+
*/
|
196 |
+
var $bitmap = 0;
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Error information
|
200 |
+
*
|
201 |
+
* @see Net_SSH2::getErrors()
|
202 |
+
* @see Net_SSH2::getLastError()
|
203 |
+
* @var String
|
204 |
+
* @access private
|
205 |
+
*/
|
206 |
+
var $errors = array();
|
207 |
+
|
208 |
+
/**
|
209 |
+
* Server Identifier
|
210 |
+
*
|
211 |
+
* @see Net_SSH2::getServerIdentification()
|
212 |
+
* @var String
|
213 |
+
* @access private
|
214 |
+
*/
|
215 |
+
var $server_identifier = '';
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Key Exchange Algorithms
|
219 |
+
*
|
220 |
+
* @see Net_SSH2::getKexAlgorithims()
|
221 |
+
* @var Array
|
222 |
+
* @access private
|
223 |
+
*/
|
224 |
+
var $kex_algorithms;
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Server Host Key Algorithms
|
228 |
+
*
|
229 |
+
* @see Net_SSH2::getServerHostKeyAlgorithms()
|
230 |
+
* @var Array
|
231 |
+
* @access private
|
232 |
+
*/
|
233 |
+
var $server_host_key_algorithms;
|
234 |
+
|
235 |
+
/**
|
236 |
+
* Encryption Algorithms: Client to Server
|
237 |
+
*
|
238 |
+
* @see Net_SSH2::getEncryptionAlgorithmsClient2Server()
|
239 |
+
* @var Array
|
240 |
+
* @access private
|
241 |
+
*/
|
242 |
+
var $encryption_algorithms_client_to_server;
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Encryption Algorithms: Server to Client
|
246 |
+
*
|
247 |
+
* @see Net_SSH2::getEncryptionAlgorithmsServer2Client()
|
248 |
+
* @var Array
|
249 |
+
* @access private
|
250 |
+
*/
|
251 |
+
var $encryption_algorithms_server_to_client;
|
252 |
+
|
253 |
+
/**
|
254 |
+
* MAC Algorithms: Client to Server
|
255 |
+
*
|
256 |
+
* @see Net_SSH2::getMACAlgorithmsClient2Server()
|
257 |
+
* @var Array
|
258 |
+
* @access private
|
259 |
+
*/
|
260 |
+
var $mac_algorithms_client_to_server;
|
261 |
+
|
262 |
+
/**
|
263 |
+
* MAC Algorithms: Server to Client
|
264 |
+
*
|
265 |
+
* @see Net_SSH2::getMACAlgorithmsServer2Client()
|
266 |
+
* @var Array
|
267 |
+
* @access private
|
268 |
+
*/
|
269 |
+
var $mac_algorithms_server_to_client;
|
270 |
+
|
271 |
+
/**
|
272 |
+
* Compression Algorithms: Client to Server
|
273 |
+
*
|
274 |
+
* @see Net_SSH2::getCompressionAlgorithmsClient2Server()
|
275 |
+
* @var Array
|
276 |
+
* @access private
|
277 |
+
*/
|
278 |
+
var $compression_algorithms_client_to_server;
|
279 |
+
|
280 |
+
/**
|
281 |
+
* Compression Algorithms: Server to Client
|
282 |
+
*
|
283 |
+
* @see Net_SSH2::getCompressionAlgorithmsServer2Client()
|
284 |
+
* @var Array
|
285 |
+
* @access private
|
286 |
+
*/
|
287 |
+
var $compression_algorithms_server_to_client;
|
288 |
+
|
289 |
+
/**
|
290 |
+
* Languages: Server to Client
|
291 |
+
*
|
292 |
+
* @see Net_SSH2::getLanguagesServer2Client()
|
293 |
+
* @var Array
|
294 |
+
* @access private
|
295 |
+
*/
|
296 |
+
var $languages_server_to_client;
|
297 |
+
|
298 |
+
/**
|
299 |
+
* Languages: Client to Server
|
300 |
+
*
|
301 |
+
* @see Net_SSH2::getLanguagesClient2Server()
|
302 |
+
* @var Array
|
303 |
+
* @access private
|
304 |
+
*/
|
305 |
+
var $languages_client_to_server;
|
306 |
+
|
307 |
+
/**
|
308 |
+
* Block Size for Server to Client Encryption
|
309 |
+
*
|
310 |
+
* "Note that the length of the concatenation of 'packet_length',
|
311 |
+
* 'padding_length', 'payload', and 'random padding' MUST be a multiple
|
312 |
+
* of the cipher block size or 8, whichever is larger. This constraint
|
313 |
+
* MUST be enforced, even when using stream ciphers."
|
314 |
+
*
|
315 |
+
* -- http://tools.ietf.org/html/rfc4253#section-6
|
316 |
+
*
|
317 |
+
* @see Net_SSH2::Net_SSH2()
|
318 |
+
* @see Net_SSH2::_send_binary_packet()
|
319 |
+
* @var Integer
|
320 |
+
* @access private
|
321 |
+
*/
|
322 |
+
var $encrypt_block_size = 8;
|
323 |
+
|
324 |
+
/**
|
325 |
+
* Block Size for Client to Server Encryption
|
326 |
+
*
|
327 |
+
* @see Net_SSH2::Net_SSH2()
|
328 |
+
* @see Net_SSH2::_get_binary_packet()
|
329 |
+
* @var Integer
|
330 |
+
* @access private
|
331 |
+
*/
|
332 |
+
var $decrypt_block_size = 8;
|
333 |
+
|
334 |
+
/**
|
335 |
+
* Server to Client Encryption Object
|
336 |
+
*
|
337 |
+
* @see Net_SSH2::_get_binary_packet()
|
338 |
+
* @var Object
|
339 |
+
* @access private
|
340 |
+
*/
|
341 |
+
var $decrypt = false;
|
342 |
+
|
343 |
+
/**
|
344 |
+
* Client to Server Encryption Object
|
345 |
+
*
|
346 |
+
* @see Net_SSH2::_send_binary_packet()
|
347 |
+
* @var Object
|
348 |
+
* @access private
|
349 |
+
*/
|
350 |
+
var $encrypt = false;
|
351 |
+
|
352 |
+
/**
|
353 |
+
* Client to Server HMAC Object
|
354 |
+
*
|
355 |
+
* @see Net_SSH2::_send_binary_packet()
|
356 |
+
* @var Object
|
357 |
+
* @access private
|
358 |
+
*/
|
359 |
+
var $hmac_create = false;
|
360 |
+
|
361 |
+
/**
|
362 |
+
* Server to Client HMAC Object
|
363 |
+
*
|
364 |
+
* @see Net_SSH2::_get_binary_packet()
|
365 |
+
* @var Object
|
366 |
+
* @access private
|
367 |
+
*/
|
368 |
+
var $hmac_check = false;
|
369 |
+
|
370 |
+
/**
|
371 |
+
* Size of server to client HMAC
|
372 |
+
*
|
373 |
+
* We need to know how big the HMAC will be for the server to client direction so that we know how many bytes to read.
|
374 |
+
* For the client to server side, the HMAC object will make the HMAC as long as it needs to be. All we need to do is
|
375 |
+
* append it.
|
376 |
+
*
|
377 |
+
* @see Net_SSH2::_get_binary_packet()
|
378 |
+
* @var Integer
|
379 |
+
* @access private
|
380 |
+
*/
|
381 |
+
var $hmac_size = false;
|
382 |
+
|
383 |
+
/**
|
384 |
+
* Server Public Host Key
|
385 |
+
*
|
386 |
+
* @see Net_SSH2::getServerPublicHostKey()
|
387 |
+
* @var String
|
388 |
+
* @access private
|
389 |
+
*/
|
390 |
+
var $server_public_host_key;
|
391 |
+
|
392 |
+
/**
|
393 |
+
* Session identifer
|
394 |
+
*
|
395 |
+
* "The exchange hash H from the first key exchange is additionally
|
396 |
+
* used as the session identifier, which is a unique identifier for
|
397 |
+
* this connection."
|
398 |
+
*
|
399 |
+
* -- http://tools.ietf.org/html/rfc4253#section-7.2
|
400 |
+
*
|
401 |
+
* @see Net_SSH2::_key_exchange()
|
402 |
+
* @var String
|
403 |
+
* @access private
|
404 |
+
*/
|
405 |
+
var $session_id = false;
|
406 |
+
|
407 |
+
/**
|
408 |
+
* Exchange hash
|
409 |
+
*
|
410 |
+
* The current exchange hash
|
411 |
+
*
|
412 |
+
* @see Net_SSH2::_key_exchange()
|
413 |
+
* @var String
|
414 |
+
* @access private
|
415 |
+
*/
|
416 |
+
var $exchange_hash = false;
|
417 |
+
|
418 |
+
/**
|
419 |
+
* Message Numbers
|
420 |
+
*
|
421 |
+
* @see Net_SSH2::Net_SSH2()
|
422 |
+
* @var Array
|
423 |
+
* @access private
|
424 |
+
*/
|
425 |
+
var $message_numbers = array();
|
426 |
+
|
427 |
+
/**
|
428 |
+
* Disconnection Message 'reason codes' defined in RFC4253
|
429 |
+
*
|
430 |
+
* @see Net_SSH2::Net_SSH2()
|
431 |
+
* @var Array
|
432 |
+
* @access private
|
433 |
+
*/
|
434 |
+
var $disconnect_reasons = array();
|
435 |
+
|
436 |
+
/**
|
437 |
+
* SSH_MSG_CHANNEL_OPEN_FAILURE 'reason codes', defined in RFC4254
|
438 |
+
*
|
439 |
+
* @see Net_SSH2::Net_SSH2()
|
440 |
+
* @var Array
|
441 |
+
* @access private
|
442 |
+
*/
|
443 |
+
var $channel_open_failure_reasons = array();
|
444 |
+
|
445 |
+
/**
|
446 |
+
* Terminal Modes
|
447 |
+
*
|
448 |
+
* @link http://tools.ietf.org/html/rfc4254#section-8
|
449 |
+
* @see Net_SSH2::Net_SSH2()
|
450 |
+
* @var Array
|
451 |
+
* @access private
|
452 |
+
*/
|
453 |
+
var $terminal_modes = array();
|
454 |
+
|
455 |
+
/**
|
456 |
+
* SSH_MSG_CHANNEL_EXTENDED_DATA's data_type_codes
|
457 |
+
*
|
458 |
+
* @link http://tools.ietf.org/html/rfc4254#section-5.2
|
459 |
+
* @see Net_SSH2::Net_SSH2()
|
460 |
+
* @var Array
|
461 |
+
* @access private
|
462 |
+
*/
|
463 |
+
var $channel_extended_data_type_codes = array();
|
464 |
+
|
465 |
+
/**
|
466 |
+
* Send Sequence Number
|
467 |
+
*
|
468 |
+
* See 'Section 6.4. Data Integrity' of rfc4253 for more info.
|
469 |
+
*
|
470 |
+
* @see Net_SSH2::_send_binary_packet()
|
471 |
+
* @var Integer
|
472 |
+
* @access private
|
473 |
+
*/
|
474 |
+
var $send_seq_no = 0;
|
475 |
+
|
476 |
+
/**
|
477 |
+
* Get Sequence Number
|
478 |
+
*
|
479 |
+
* See 'Section 6.4. Data Integrity' of rfc4253 for more info.
|
480 |
+
*
|
481 |
+
* @see Net_SSH2::_get_binary_packet()
|
482 |
+
* @var Integer
|
483 |
+
* @access private
|
484 |
+
*/
|
485 |
+
var $get_seq_no = 0;
|
486 |
+
|
487 |
+
/**
|
488 |
+
* Server Channels
|
489 |
+
*
|
490 |
+
* Maps client channels to server channels
|
491 |
+
*
|
492 |
+
* @see Net_SSH2::_get_channel_packet()
|
493 |
+
* @see Net_SSH2::exec()
|
494 |
+
* @var Array
|
495 |
+
* @access private
|
496 |
+
*/
|
497 |
+
var $server_channels = array();
|
498 |
+
|
499 |
+
/**
|
500 |
+
* Channel Buffers
|
501 |
+
*
|
502 |
+
* If a client requests a packet from one channel but receives two packets from another those packets should
|
503 |
+
* be placed in a buffer
|
504 |
+
*
|
505 |
+
* @see Net_SSH2::_get_channel_packet()
|
506 |
+
* @see Net_SSH2::exec()
|
507 |
+
* @var Array
|
508 |
+
* @access private
|
509 |
+
*/
|
510 |
+
var $channel_buffers = array();
|
511 |
+
|
512 |
+
/**
|
513 |
+
* Channel Status
|
514 |
+
*
|
515 |
+
* Contains the type of the last sent message
|
516 |
+
*
|
517 |
+
* @see Net_SSH2::_get_channel_packet()
|
518 |
+
* @var Array
|
519 |
+
* @access private
|
520 |
+
*/
|
521 |
+
var $channel_status = array();
|
522 |
+
|
523 |
+
/**
|
524 |
+
* Packet Size
|
525 |
+
*
|
526 |
+
* Maximum packet size indexed by channel
|
527 |
+
*
|
528 |
+
* @see Net_SSH2::_send_channel_packet()
|
529 |
+
* @var Array
|
530 |
+
* @access private
|
531 |
+
*/
|
532 |
+
var $packet_size_client_to_server = array();
|
533 |
+
|
534 |
+
/**
|
535 |
+
* Message Number Log
|
536 |
+
*
|
537 |
+
* @see Net_SSH2::getLog()
|
538 |
+
* @var Array
|
539 |
+
* @access private
|
540 |
+
*/
|
541 |
+
var $message_number_log = array();
|
542 |
+
|
543 |
+
/**
|
544 |
+
* Message Log
|
545 |
+
*
|
546 |
+
* @see Net_SSH2::getLog()
|
547 |
+
* @var Array
|
548 |
+
* @access private
|
549 |
+
*/
|
550 |
+
var $message_log = array();
|
551 |
+
|
552 |
+
/**
|
553 |
+
* The Window Size
|
554 |
+
*
|
555 |
+
* Bytes the other party can send before it must wait for the window to be adjusted (0x7FFFFFFF = 4GB)
|
556 |
+
*
|
557 |
+
* @var Integer
|
558 |
+
* @see Net_SSH2::_send_channel_packet()
|
559 |
+
* @see Net_SSH2::exec()
|
560 |
+
* @access private
|
561 |
+
*/
|
562 |
+
var $window_size = 0x7FFFFFFF;
|
563 |
+
|
564 |
+
/**
|
565 |
+
* Window size
|
566 |
+
*
|
567 |
+
* Window size indexed by channel
|
568 |
+
*
|
569 |
+
* @see Net_SSH2::_send_channel_packet()
|
570 |
+
* @var Array
|
571 |
+
* @access private
|
572 |
+
*/
|
573 |
+
var $window_size_client_to_server = array();
|
574 |
+
|
575 |
+
/**
|
576 |
+
* Server signature
|
577 |
+
*
|
578 |
+
* Verified against $this->session_id
|
579 |
+
*
|
580 |
+
* @see Net_SSH2::getServerPublicHostKey()
|
581 |
+
* @var String
|
582 |
+
* @access private
|
583 |
+
*/
|
584 |
+
var $signature = '';
|
585 |
+
|
586 |
+
/**
|
587 |
+
* Server signature format
|
588 |
+
*
|
589 |
+
* ssh-rsa or ssh-dss.
|
590 |
+
*
|
591 |
+
* @see Net_SSH2::getServerPublicHostKey()
|
592 |
+
* @var String
|
593 |
+
* @access private
|
594 |
+
*/
|
595 |
+
var $signature_format = '';
|
596 |
+
|
597 |
+
/**
|
598 |
+
* Interactive Buffer
|
599 |
+
*
|
600 |
+
* @see Net_SSH2::read()
|
601 |
+
* @var Array
|
602 |
+
* @access private
|
603 |
+
*/
|
604 |
+
var $interactiveBuffer = '';
|
605 |
+
|
606 |
+
/**
|
607 |
+
* Default Constructor.
|
608 |
+
*
|
609 |
+
* Connects to an SSHv2 server
|
610 |
+
*
|
611 |
+
* @param String $host
|
612 |
+
* @param optional Integer $port
|
613 |
+
* @param optional Integer $timeout
|
614 |
+
* @return Net_SSH2
|
615 |
+
* @access public
|
616 |
+
*/
|
617 |
+
function Net_SSH2($host, $port = 22, $timeout = 10)
|
618 |
+
{
|
619 |
+
$this->message_numbers = array(
|
620 |
+
1 => 'NET_SSH2_MSG_DISCONNECT',
|
621 |
+
2 => 'NET_SSH2_MSG_IGNORE',
|
622 |
+
3 => 'NET_SSH2_MSG_UNIMPLEMENTED',
|
623 |
+
4 => 'NET_SSH2_MSG_DEBUG',
|
624 |
+
5 => 'NET_SSH2_MSG_SERVICE_REQUEST',
|
625 |
+
6 => 'NET_SSH2_MSG_SERVICE_ACCEPT',
|
626 |
+
20 => 'NET_SSH2_MSG_KEXINIT',
|
627 |
+
21 => 'NET_SSH2_MSG_NEWKEYS',
|
628 |
+
30 => 'NET_SSH2_MSG_KEXDH_INIT',
|
629 |
+
31 => 'NET_SSH2_MSG_KEXDH_REPLY',
|
630 |
+
50 => 'NET_SSH2_MSG_USERAUTH_REQUEST',
|
631 |
+
51 => 'NET_SSH2_MSG_USERAUTH_FAILURE',
|
632 |
+
52 => 'NET_SSH2_MSG_USERAUTH_SUCCESS',
|
633 |
+
53 => 'NET_SSH2_MSG_USERAUTH_BANNER',
|
634 |
+
|
635 |
+
80 => 'NET_SSH2_MSG_GLOBAL_REQUEST',
|
636 |
+
81 => 'NET_SSH2_MSG_REQUEST_SUCCESS',
|
637 |
+
82 => 'NET_SSH2_MSG_REQUEST_FAILURE',
|
638 |
+
90 => 'NET_SSH2_MSG_CHANNEL_OPEN',
|
639 |
+
91 => 'NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION',
|
640 |
+
92 => 'NET_SSH2_MSG_CHANNEL_OPEN_FAILURE',
|
641 |
+
93 => 'NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST',
|
642 |
+
94 => 'NET_SSH2_MSG_CHANNEL_DATA',
|
643 |
+
95 => 'NET_SSH2_MSG_CHANNEL_EXTENDED_DATA',
|
644 |
+
96 => 'NET_SSH2_MSG_CHANNEL_EOF',
|
645 |
+
97 => 'NET_SSH2_MSG_CHANNEL_CLOSE',
|
646 |
+
98 => 'NET_SSH2_MSG_CHANNEL_REQUEST',
|
647 |
+
99 => 'NET_SSH2_MSG_CHANNEL_SUCCESS',
|
648 |
+
100 => 'NET_SSH2_MSG_CHANNEL_FAILURE'
|
649 |
+
);
|
650 |
+
$this->disconnect_reasons = array(
|
651 |
+
1 => 'NET_SSH2_DISCONNECT_HOST_NOT_ALLOWED_TO_CONNECT',
|
652 |
+
2 => 'NET_SSH2_DISCONNECT_PROTOCOL_ERROR',
|
653 |
+
3 => 'NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED',
|
654 |
+
4 => 'NET_SSH2_DISCONNECT_RESERVED',
|
655 |
+
5 => 'NET_SSH2_DISCONNECT_MAC_ERROR',
|
656 |
+
6 => 'NET_SSH2_DISCONNECT_COMPRESSION_ERROR',
|
657 |
+
7 => 'NET_SSH2_DISCONNECT_SERVICE_NOT_AVAILABLE',
|
658 |
+
8 => 'NET_SSH2_DISCONNECT_PROTOCOL_VERSION_NOT_SUPPORTED',
|
659 |
+
9 => 'NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE',
|
660 |
+
10 => 'NET_SSH2_DISCONNECT_CONNECTION_LOST',
|
661 |
+
11 => 'NET_SSH2_DISCONNECT_BY_APPLICATION',
|
662 |
+
12 => 'NET_SSH2_DISCONNECT_TOO_MANY_CONNECTIONS',
|
663 |
+
13 => 'NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER',
|
664 |
+
14 => 'NET_SSH2_DISCONNECT_NO_MORE_AUTH_METHODS_AVAILABLE',
|
665 |
+
15 => 'NET_SSH2_DISCONNECT_ILLEGAL_USER_NAME'
|
666 |
+
);
|
667 |
+
$this->channel_open_failure_reasons = array(
|
668 |
+
1 => 'NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED'
|
669 |
+
);
|
670 |
+
$this->terminal_modes = array(
|
671 |
+
0 => 'NET_SSH2_TTY_OP_END'
|
672 |
+
);
|
673 |
+
$this->channel_extended_data_type_codes = array(
|
674 |
+
1 => 'NET_SSH2_EXTENDED_DATA_STDERR'
|
675 |
+
);
|
676 |
+
|
677 |
+
$this->_define_array(
|
678 |
+
$this->message_numbers,
|
679 |
+
$this->disconnect_reasons,
|
680 |
+
$this->channel_open_failure_reasons,
|
681 |
+
$this->terminal_modes,
|
682 |
+
$this->channel_extended_data_type_codes,
|
683 |
+
array(60 => 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ'),
|
684 |
+
array(60 => 'NET_SSH2_MSG_USERAUTH_PK_OK'),
|
685 |
+
array(60 => 'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
|
686 |
+
61 => 'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE')
|
687 |
+
);
|
688 |
+
|
689 |
+
$this->fsock = @fsockopen($host, $port, $errno, $errstr, $timeout);
|
690 |
+
if (!$this->fsock) {
|
691 |
+
user_error(rtrim("Cannot connect to $host. Error $errno. $errstr"), E_USER_NOTICE);
|
692 |
+
return;
|
693 |
+
}
|
694 |
+
|
695 |
+
/* According to the SSH2 specs,
|
696 |
+
|
697 |
+
"The server MAY send other lines of data before sending the version
|
698 |
+
string. Each line SHOULD be terminated by a Carriage Return and Line
|
699 |
+
Feed. Such lines MUST NOT begin with "SSH-", and SHOULD be encoded
|
700 |
+
in ISO-10646 UTF-8 [RFC3629] (language is not specified). Clients
|
701 |
+
MUST be able to process such lines." */
|
702 |
+
$temp = '';
|
703 |
+
$extra = '';
|
704 |
+
while (!feof($this->fsock) && !preg_match('#^SSH-(\d\.\d+)#', $temp, $matches)) {
|
705 |
+
if (substr($temp, -2) == "\r\n") {
|
706 |
+
$extra.= $temp;
|
707 |
+
$temp = '';
|
708 |
+
}
|
709 |
+
$temp.= fgets($this->fsock, 255);
|
710 |
+
}
|
711 |
+
|
712 |
+
if (feof($this->fsock)) {
|
713 |
+
user_error('Connection closed by server', E_USER_NOTICE);
|
714 |
+
return false;
|
715 |
+
}
|
716 |
+
|
717 |
+
$ext = array();
|
718 |
+
if (extension_loaded('mcrypt')) {
|
719 |
+
$ext[] = 'mcrypt';
|
720 |
+
}
|
721 |
+
if (extension_loaded('gmp')) {
|
722 |
+
$ext[] = 'gmp';
|
723 |
+
} else if (extension_loaded('bcmath')) {
|
724 |
+
$ext[] = 'bcmath';
|
725 |
+
}
|
726 |
+
|
727 |
+
if (!empty($ext)) {
|
728 |
+
$this->identifier.= ' (' . implode(', ', $ext) . ')';
|
729 |
+
}
|
730 |
+
|
731 |
+
if (defined('NET_SSH2_LOGGING')) {
|
732 |
+
$this->message_number_log[] = '<-';
|
733 |
+
$this->message_number_log[] = '->';
|
734 |
+
|
735 |
+
if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
|
736 |
+
$this->message_log[] = $temp;
|
737 |
+
$this->message_log[] = $this->identifier . "\r\n";
|
738 |
+
}
|
739 |
+
}
|
740 |
+
|
741 |
+
$this->server_identifier = trim($temp, "\r\n");
|
742 |
+
if (!empty($extra)) {
|
743 |
+
$this->errors[] = utf8_decode($extra);
|
744 |
+
}
|
745 |
+
|
746 |
+
if ($matches[1] != '1.99' && $matches[1] != '2.0') {
|
747 |
+
user_error("Cannot connect to SSH $matches[1] servers", E_USER_NOTICE);
|
748 |
+
return;
|
749 |
+
}
|
750 |
+
|
751 |
+
fputs($this->fsock, $this->identifier . "\r\n");
|
752 |
+
|
753 |
+
$response = $this->_get_binary_packet();
|
754 |
+
if ($response === false) {
|
755 |
+
user_error('Connection closed by server', E_USER_NOTICE);
|
756 |
+
return;
|
757 |
+
}
|
758 |
+
|
759 |
+
if (ord($response[0]) != NET_SSH2_MSG_KEXINIT) {
|
760 |
+
user_error('Expected SSH_MSG_KEXINIT', E_USER_NOTICE);
|
761 |
+
return;
|
762 |
+
}
|
763 |
+
|
764 |
+
if (!$this->_key_exchange($response)) {
|
765 |
+
return;
|
766 |
+
}
|
767 |
+
|
768 |
+
$this->bitmap = NET_SSH2_MASK_CONSTRUCTOR;
|
769 |
+
}
|
770 |
+
|
771 |
+
/**
|
772 |
+
* Key Exchange
|
773 |
+
*
|
774 |
+
* @param String $kexinit_payload_server
|
775 |
+
* @access private
|
776 |
+
*/
|
777 |
+
function _key_exchange($kexinit_payload_server)
|
778 |
+
{
|
779 |
+
static $kex_algorithms = array(
|
780 |
+
'diffie-hellman-group1-sha1', // REQUIRED
|
781 |
+
'diffie-hellman-group14-sha1' // REQUIRED
|
782 |
+
);
|
783 |
+
|
784 |
+
static $server_host_key_algorithms = array(
|
785 |
+
'ssh-rsa', // RECOMMENDED sign Raw RSA Key
|
786 |
+
'ssh-dss' // REQUIRED sign Raw DSS Key
|
787 |
+
);
|
788 |
+
|
789 |
+
static $encryption_algorithms = array(
|
790 |
+
// from <http://tools.ietf.org/html/rfc4345#section-4>:
|
791 |
+
'arcfour256',
|
792 |
+
'arcfour128',
|
793 |
+
|
794 |
+
'arcfour', // OPTIONAL the ARCFOUR stream cipher with a 128-bit key
|
795 |
+
|
796 |
+
'aes128-cbc', // RECOMMENDED AES with a 128-bit key
|
797 |
+
'aes192-cbc', // OPTIONAL AES with a 192-bit key
|
798 |
+
'aes256-cbc', // OPTIONAL AES in CBC mode, with a 256-bit key
|
799 |
+
|
800 |
+
// from <http://tools.ietf.org/html/rfc4344#section-4>:
|
801 |
+
'aes128-ctr', // RECOMMENDED AES (Rijndael) in SDCTR mode, with 128-bit key
|
802 |
+
'aes192-ctr', // RECOMMENDED AES with 192-bit key
|
803 |
+
'aes256-ctr', // RECOMMENDED AES with 256-bit key
|
804 |
+
'3des-ctr', // RECOMMENDED Three-key 3DES in SDCTR mode
|
805 |
+
|
806 |
+
'3des-cbc', // REQUIRED three-key 3DES in CBC mode
|
807 |
+
'none' // OPTIONAL no encryption; NOT RECOMMENDED
|
808 |
+
);
|
809 |
+
|
810 |
+
static $mac_algorithms = array(
|
811 |
+
'hmac-sha1-96', // RECOMMENDED first 96 bits of HMAC-SHA1 (digest length = 12, key length = 20)
|
812 |
+
'hmac-sha1', // REQUIRED HMAC-SHA1 (digest length = key length = 20)
|
813 |
+
'hmac-md5-96', // OPTIONAL first 96 bits of HMAC-MD5 (digest length = 12, key length = 16)
|
814 |
+
'hmac-md5', // OPTIONAL HMAC-MD5 (digest length = key length = 16)
|
815 |
+
'none' // OPTIONAL no MAC; NOT RECOMMENDED
|
816 |
+
);
|
817 |
+
|
818 |
+
static $compression_algorithms = array(
|
819 |
+
'none' // REQUIRED no compression
|
820 |
+
//'zlib' // OPTIONAL ZLIB (LZ77) compression
|
821 |
+
);
|
822 |
+
|
823 |
+
static $str_kex_algorithms, $str_server_host_key_algorithms,
|
824 |
+
$encryption_algorithms_server_to_client, $mac_algorithms_server_to_client, $compression_algorithms_server_to_client,
|
825 |
+
$encryption_algorithms_client_to_server, $mac_algorithms_client_to_server, $compression_algorithms_client_to_server;
|
826 |
+
|
827 |
+
if (empty($str_kex_algorithms)) {
|
828 |
+
$str_kex_algorithms = implode(',', $kex_algorithms);
|
829 |
+
$str_server_host_key_algorithms = implode(',', $server_host_key_algorithms);
|
830 |
+
$encryption_algorithms_server_to_client = $encryption_algorithms_client_to_server = implode(',', $encryption_algorithms);
|
831 |
+
$mac_algorithms_server_to_client = $mac_algorithms_client_to_server = implode(',', $mac_algorithms);
|
832 |
+
$compression_algorithms_server_to_client = $compression_algorithms_client_to_server = implode(',', $compression_algorithms);
|
833 |
+
}
|
834 |
+
|
835 |
+
$client_cookie = '';
|
836 |
+
for ($i = 0; $i < 16; $i++) {
|
837 |
+
$client_cookie.= chr(crypt_random(0, 255));
|
838 |
+
}
|
839 |
+
|
840 |
+
$response = $kexinit_payload_server;
|
841 |
+
$this->_string_shift($response, 1); // skip past the message number (it should be SSH_MSG_KEXINIT)
|
842 |
+
$server_cookie = $this->_string_shift($response, 16);
|
843 |
+
|
844 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
845 |
+
$this->kex_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
|
846 |
+
|
847 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
848 |
+
$this->server_host_key_algorithms = explode(',', $this->_string_shift($response, $temp['length']));
|
849 |
+
|
850 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
851 |
+
$this->encryption_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
|
852 |
+
|
853 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
854 |
+
$this->encryption_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
|
855 |
+
|
856 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
857 |
+
$this->mac_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
|
858 |
+
|
859 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
860 |
+
$this->mac_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
|
861 |
+
|
862 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
863 |
+
$this->compression_algorithms_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
|
864 |
+
|
865 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
866 |
+
$this->compression_algorithms_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
|
867 |
+
|
868 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
869 |
+
$this->languages_client_to_server = explode(',', $this->_string_shift($response, $temp['length']));
|
870 |
+
|
871 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
872 |
+
$this->languages_server_to_client = explode(',', $this->_string_shift($response, $temp['length']));
|
873 |
+
|
874 |
+
extract(unpack('Cfirst_kex_packet_follows', $this->_string_shift($response, 1)));
|
875 |
+
$first_kex_packet_follows = $first_kex_packet_follows != 0;
|
876 |
+
|
877 |
+
// the sending of SSH2_MSG_KEXINIT could go in one of two places. this is the second place.
|
878 |
+
$kexinit_payload_client = pack('Ca*Na*Na*Na*Na*Na*Na*Na*Na*Na*Na*CN',
|
879 |
+
NET_SSH2_MSG_KEXINIT, $client_cookie, strlen($str_kex_algorithms), $str_kex_algorithms,
|
880 |
+
strlen($str_server_host_key_algorithms), $str_server_host_key_algorithms, strlen($encryption_algorithms_client_to_server),
|
881 |
+
$encryption_algorithms_client_to_server, strlen($encryption_algorithms_server_to_client), $encryption_algorithms_server_to_client,
|
882 |
+
strlen($mac_algorithms_client_to_server), $mac_algorithms_client_to_server, strlen($mac_algorithms_server_to_client),
|
883 |
+
$mac_algorithms_server_to_client, strlen($compression_algorithms_client_to_server), $compression_algorithms_client_to_server,
|
884 |
+
strlen($compression_algorithms_server_to_client), $compression_algorithms_server_to_client, 0, '', 0, '',
|
885 |
+
0, 0
|
886 |
+
);
|
887 |
+
|
888 |
+
if (!$this->_send_binary_packet($kexinit_payload_client)) {
|
889 |
+
return false;
|
890 |
+
}
|
891 |
+
// here ends the second place.
|
892 |
+
|
893 |
+
// we need to decide upon the symmetric encryption algorithms before we do the diffie-hellman key exchange
|
894 |
+
for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_server_to_client); $i++);
|
895 |
+
if ($i == count($encryption_algorithms)) {
|
896 |
+
user_error('No compatible server to client encryption algorithms found', E_USER_NOTICE);
|
897 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
898 |
+
}
|
899 |
+
|
900 |
+
// we don't initialize any crypto-objects, yet - we do that, later. for now, we need the lengths to make the
|
901 |
+
// diffie-hellman key exchange as fast as possible
|
902 |
+
$decrypt = $encryption_algorithms[$i];
|
903 |
+
switch ($decrypt) {
|
904 |
+
case '3des-cbc':
|
905 |
+
case '3des-ctr':
|
906 |
+
$decryptKeyLength = 24; // eg. 192 / 8
|
907 |
+
break;
|
908 |
+
case 'aes256-cbc':
|
909 |
+
case 'aes256-ctr':
|
910 |
+
$decryptKeyLength = 32; // eg. 256 / 8
|
911 |
+
break;
|
912 |
+
case 'aes192-cbc':
|
913 |
+
case 'aes192-ctr':
|
914 |
+
$decryptKeyLength = 24; // eg. 192 / 8
|
915 |
+
break;
|
916 |
+
case 'aes128-cbc':
|
917 |
+
case 'aes128-ctr':
|
918 |
+
$decryptKeyLength = 16; // eg. 128 / 8
|
919 |
+
break;
|
920 |
+
case 'arcfour':
|
921 |
+
case 'arcfour128':
|
922 |
+
$decryptKeyLength = 16; // eg. 128 / 8
|
923 |
+
break;
|
924 |
+
case 'arcfour256':
|
925 |
+
$decryptKeyLength = 32; // eg. 128 / 8
|
926 |
+
break;
|
927 |
+
case 'none';
|
928 |
+
$decryptKeyLength = 0;
|
929 |
+
}
|
930 |
+
|
931 |
+
for ($i = 0; $i < count($encryption_algorithms) && !in_array($encryption_algorithms[$i], $this->encryption_algorithms_client_to_server); $i++);
|
932 |
+
if ($i == count($encryption_algorithms)) {
|
933 |
+
user_error('No compatible client to server encryption algorithms found', E_USER_NOTICE);
|
934 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
935 |
+
}
|
936 |
+
|
937 |
+
$encrypt = $encryption_algorithms[$i];
|
938 |
+
switch ($encrypt) {
|
939 |
+
case '3des-cbc':
|
940 |
+
case '3des-ctr':
|
941 |
+
$encryptKeyLength = 24;
|
942 |
+
break;
|
943 |
+
case 'aes256-cbc':
|
944 |
+
case 'aes256-ctr':
|
945 |
+
$encryptKeyLength = 32;
|
946 |
+
break;
|
947 |
+
case 'aes192-cbc':
|
948 |
+
case 'aes192-ctr':
|
949 |
+
$encryptKeyLength = 24;
|
950 |
+
break;
|
951 |
+
case 'aes128-cbc':
|
952 |
+
case 'aes128-ctr':
|
953 |
+
$encryptKeyLength = 16;
|
954 |
+
break;
|
955 |
+
case 'arcfour':
|
956 |
+
case 'arcfour128':
|
957 |
+
$encryptKeyLength = 16;
|
958 |
+
break;
|
959 |
+
case 'arcfour256':
|
960 |
+
$encryptKeyLength = 32;
|
961 |
+
break;
|
962 |
+
case 'none';
|
963 |
+
$encryptKeyLength = 0;
|
964 |
+
}
|
965 |
+
|
966 |
+
$keyLength = $decryptKeyLength > $encryptKeyLength ? $decryptKeyLength : $encryptKeyLength;
|
967 |
+
|
968 |
+
// through diffie-hellman key exchange a symmetric key is obtained
|
969 |
+
for ($i = 0; $i < count($kex_algorithms) && !in_array($kex_algorithms[$i], $this->kex_algorithms); $i++);
|
970 |
+
if ($i == count($kex_algorithms)) {
|
971 |
+
user_error('No compatible key exchange algorithms found', E_USER_NOTICE);
|
972 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
973 |
+
}
|
974 |
+
|
975 |
+
switch ($kex_algorithms[$i]) {
|
976 |
+
// see http://tools.ietf.org/html/rfc2409#section-6.2 and
|
977 |
+
// http://tools.ietf.org/html/rfc2412, appendex E
|
978 |
+
case 'diffie-hellman-group1-sha1':
|
979 |
+
$p = pack('H256', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
|
980 |
+
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
|
981 |
+
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
|
982 |
+
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381FFFFFFFFFFFFFFFF');
|
983 |
+
$keyLength = $keyLength < 160 ? $keyLength : 160;
|
984 |
+
$hash = 'sha1';
|
985 |
+
break;
|
986 |
+
// see http://tools.ietf.org/html/rfc3526#section-3
|
987 |
+
case 'diffie-hellman-group14-sha1':
|
988 |
+
$p = pack('H512', 'FFFFFFFFFFFFFFFFC90FDAA22168C234C4C6628B80DC1CD129024E088A67CC74' .
|
989 |
+
'020BBEA63B139B22514A08798E3404DDEF9519B3CD3A431B302B0A6DF25F1437' .
|
990 |
+
'4FE1356D6D51C245E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED' .
|
991 |
+
'EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE45B3DC2007CB8A163BF05' .
|
992 |
+
'98DA48361C55D39A69163FA8FD24CF5F83655D23DCA3AD961C62F356208552BB' .
|
993 |
+
'9ED529077096966D670C354E4ABC9804F1746C08CA18217C32905E462E36CE3B' .
|
994 |
+
'E39E772C180E86039B2783A2EC07A28FB5C55DF06F4C52C9DE2BCBF695581718' .
|
995 |
+
'3995497CEA956AE515D2261898FA051015728E5A8AACAA68FFFFFFFFFFFFFFFF');
|
996 |
+
$keyLength = $keyLength < 160 ? $keyLength : 160;
|
997 |
+
$hash = 'sha1';
|
998 |
+
}
|
999 |
+
|
1000 |
+
$p = new Math_BigInteger($p, 256);
|
1001 |
+
//$q = $p->bitwise_rightShift(1);
|
1002 |
+
|
1003 |
+
/* To increase the speed of the key exchange, both client and server may
|
1004 |
+
reduce the size of their private exponents. It should be at least
|
1005 |
+
twice as long as the key material that is generated from the shared
|
1006 |
+
secret. For more details, see the paper by van Oorschot and Wiener
|
1007 |
+
[VAN-OORSCHOT].
|
1008 |
+
|
1009 |
+
-- http://tools.ietf.org/html/rfc4419#section-6.2 */
|
1010 |
+
$q = new Math_BigInteger(1);
|
1011 |
+
$q = $q->bitwise_leftShift(2 * $keyLength);
|
1012 |
+
$q = $q->subtract(new Math_BigInteger(1));
|
1013 |
+
|
1014 |
+
$g = new Math_BigInteger(2);
|
1015 |
+
$x = new Math_BigInteger();
|
1016 |
+
$x->setRandomGenerator('crypt_random');
|
1017 |
+
$x = $x->random(new Math_BigInteger(1), $q);
|
1018 |
+
$e = $g->modPow($x, $p);
|
1019 |
+
|
1020 |
+
$eBytes = $e->toBytes(true);
|
1021 |
+
$data = pack('CNa*', NET_SSH2_MSG_KEXDH_INIT, strlen($eBytes), $eBytes);
|
1022 |
+
|
1023 |
+
if (!$this->_send_binary_packet($data)) {
|
1024 |
+
user_error('Connection closed by server', E_USER_NOTICE);
|
1025 |
+
return false;
|
1026 |
+
}
|
1027 |
+
|
1028 |
+
$response = $this->_get_binary_packet();
|
1029 |
+
if ($response === false) {
|
1030 |
+
user_error('Connection closed by server', E_USER_NOTICE);
|
1031 |
+
return false;
|
1032 |
+
}
|
1033 |
+
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
1034 |
+
|
1035 |
+
if ($type != NET_SSH2_MSG_KEXDH_REPLY) {
|
1036 |
+
user_error('Expected SSH_MSG_KEXDH_REPLY', E_USER_NOTICE);
|
1037 |
+
return false;
|
1038 |
+
}
|
1039 |
+
|
1040 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
1041 |
+
$this->server_public_host_key = $server_public_host_key = $this->_string_shift($response, $temp['length']);
|
1042 |
+
|
1043 |
+
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
1044 |
+
$public_key_format = $this->_string_shift($server_public_host_key, $temp['length']);
|
1045 |
+
|
1046 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
1047 |
+
$fBytes = $this->_string_shift($response, $temp['length']);
|
1048 |
+
$f = new Math_BigInteger($fBytes, -256);
|
1049 |
+
|
1050 |
+
$temp = unpack('Nlength', $this->_string_shift($response, 4));
|
1051 |
+
$this->signature = $this->_string_shift($response, $temp['length']);
|
1052 |
+
|
1053 |
+
$temp = unpack('Nlength', $this->_string_shift($this->signature, 4));
|
1054 |
+
$this->signature_format = $this->_string_shift($this->signature, $temp['length']);
|
1055 |
+
|
1056 |
+
$key = $f->modPow($x, $p);
|
1057 |
+
$keyBytes = $key->toBytes(true);
|
1058 |
+
|
1059 |
+
$this->exchange_hash = pack('Na*Na*Na*Na*Na*Na*Na*Na*',
|
1060 |
+
strlen($this->identifier), $this->identifier, strlen($this->server_identifier), $this->server_identifier,
|
1061 |
+
strlen($kexinit_payload_client), $kexinit_payload_client, strlen($kexinit_payload_server),
|
1062 |
+
$kexinit_payload_server, strlen($this->server_public_host_key), $this->server_public_host_key, strlen($eBytes),
|
1063 |
+
$eBytes, strlen($fBytes), $fBytes, strlen($keyBytes), $keyBytes
|
1064 |
+
);
|
1065 |
+
|
1066 |
+
$this->exchange_hash = pack('H*', $hash($this->exchange_hash));
|
1067 |
+
|
1068 |
+
if ($this->session_id === false) {
|
1069 |
+
$this->session_id = $this->exchange_hash;
|
1070 |
+
}
|
1071 |
+
|
1072 |
+
for ($i = 0; $i < count($server_host_key_algorithms) && !in_array($server_host_key_algorithms[$i], $this->server_host_key_algorithms); $i++);
|
1073 |
+
if ($i == count($server_host_key_algorithms)) {
|
1074 |
+
user_error('No compatible server host key algorithms found', E_USER_NOTICE);
|
1075 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
1076 |
+
}
|
1077 |
+
|
1078 |
+
if ($public_key_format != $server_host_key_algorithms[$i] || $this->signature_format != $server_host_key_algorithms[$i]) {
|
1079 |
+
user_error('Sever Host Key Algorithm Mismatch', E_USER_NOTICE);
|
1080 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
1081 |
+
}
|
1082 |
+
|
1083 |
+
$packet = pack('C',
|
1084 |
+
NET_SSH2_MSG_NEWKEYS
|
1085 |
+
);
|
1086 |
+
|
1087 |
+
if (!$this->_send_binary_packet($packet)) {
|
1088 |
+
return false;
|
1089 |
+
}
|
1090 |
+
|
1091 |
+
$response = $this->_get_binary_packet();
|
1092 |
+
|
1093 |
+
if ($response === false) {
|
1094 |
+
user_error('Connection closed by server', E_USER_NOTICE);
|
1095 |
+
return false;
|
1096 |
+
}
|
1097 |
+
|
1098 |
+
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
1099 |
+
|
1100 |
+
if ($type != NET_SSH2_MSG_NEWKEYS) {
|
1101 |
+
user_error('Expected SSH_MSG_NEWKEYS', E_USER_NOTICE);
|
1102 |
+
return false;
|
1103 |
+
}
|
1104 |
+
|
1105 |
+
switch ($encrypt) {
|
1106 |
+
case '3des-cbc':
|
1107 |
+
$this->encrypt = new Crypt_TripleDES();
|
1108 |
+
// $this->encrypt_block_size = 64 / 8 == the default
|
1109 |
+
break;
|
1110 |
+
case '3des-ctr':
|
1111 |
+
$this->encrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
|
1112 |
+
// $this->encrypt_block_size = 64 / 8 == the default
|
1113 |
+
break;
|
1114 |
+
case 'aes256-cbc':
|
1115 |
+
case 'aes192-cbc':
|
1116 |
+
case 'aes128-cbc':
|
1117 |
+
$this->encrypt = new Crypt_AES();
|
1118 |
+
$this->encrypt_block_size = 16; // eg. 128 / 8
|
1119 |
+
break;
|
1120 |
+
case 'aes256-ctr':
|
1121 |
+
case 'aes192-ctr':
|
1122 |
+
case 'aes128-ctr':
|
1123 |
+
$this->encrypt = new Crypt_AES(CRYPT_AES_MODE_CTR);
|
1124 |
+
$this->encrypt_block_size = 16; // eg. 128 / 8
|
1125 |
+
break;
|
1126 |
+
case 'arcfour':
|
1127 |
+
case 'arcfour128':
|
1128 |
+
case 'arcfour256':
|
1129 |
+
$this->encrypt = new Crypt_RC4();
|
1130 |
+
break;
|
1131 |
+
case 'none';
|
1132 |
+
//$this->encrypt = new Crypt_Null();
|
1133 |
+
}
|
1134 |
+
|
1135 |
+
switch ($decrypt) {
|
1136 |
+
case '3des-cbc':
|
1137 |
+
$this->decrypt = new Crypt_TripleDES();
|
1138 |
+
break;
|
1139 |
+
case '3des-ctr':
|
1140 |
+
$this->decrypt = new Crypt_TripleDES(CRYPT_DES_MODE_CTR);
|
1141 |
+
break;
|
1142 |
+
case 'aes256-cbc':
|
1143 |
+
case 'aes192-cbc':
|
1144 |
+
case 'aes128-cbc':
|
1145 |
+
$this->decrypt = new Crypt_AES();
|
1146 |
+
$this->decrypt_block_size = 16;
|
1147 |
+
break;
|
1148 |
+
case 'aes256-ctr':
|
1149 |
+
case 'aes192-ctr':
|
1150 |
+
case 'aes128-ctr':
|
1151 |
+
$this->decrypt = new Crypt_AES(CRYPT_AES_MODE_CTR);
|
1152 |
+
$this->decrypt_block_size = 16;
|
1153 |
+
break;
|
1154 |
+
case 'arcfour':
|
1155 |
+
case 'arcfour128':
|
1156 |
+
case 'arcfour256':
|
1157 |
+
$this->decrypt = new Crypt_RC4();
|
1158 |
+
break;
|
1159 |
+
case 'none';
|
1160 |
+
//$this->decrypt = new Crypt_Null();
|
1161 |
+
}
|
1162 |
+
|
1163 |
+
$keyBytes = pack('Na*', strlen($keyBytes), $keyBytes);
|
1164 |
+
|
1165 |
+
if ($this->encrypt) {
|
1166 |
+
$this->encrypt->enableContinuousBuffer();
|
1167 |
+
$this->encrypt->disablePadding();
|
1168 |
+
|
1169 |
+
$iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'A' . $this->session_id));
|
1170 |
+
while ($this->encrypt_block_size > strlen($iv)) {
|
1171 |
+
$iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv));
|
1172 |
+
}
|
1173 |
+
$this->encrypt->setIV(substr($iv, 0, $this->encrypt_block_size));
|
1174 |
+
|
1175 |
+
$key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'C' . $this->session_id));
|
1176 |
+
while ($encryptKeyLength > strlen($key)) {
|
1177 |
+
$key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key));
|
1178 |
+
}
|
1179 |
+
$this->encrypt->setKey(substr($key, 0, $encryptKeyLength));
|
1180 |
+
}
|
1181 |
+
|
1182 |
+
if ($this->decrypt) {
|
1183 |
+
$this->decrypt->enableContinuousBuffer();
|
1184 |
+
$this->decrypt->disablePadding();
|
1185 |
+
|
1186 |
+
$iv = pack('H*', $hash($keyBytes . $this->exchange_hash . 'B' . $this->session_id));
|
1187 |
+
while ($this->decrypt_block_size > strlen($iv)) {
|
1188 |
+
$iv.= pack('H*', $hash($keyBytes . $this->exchange_hash . $iv));
|
1189 |
+
}
|
1190 |
+
$this->decrypt->setIV(substr($iv, 0, $this->decrypt_block_size));
|
1191 |
+
|
1192 |
+
$key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'D' . $this->session_id));
|
1193 |
+
while ($decryptKeyLength > strlen($key)) {
|
1194 |
+
$key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key));
|
1195 |
+
}
|
1196 |
+
$this->decrypt->setKey(substr($key, 0, $decryptKeyLength));
|
1197 |
+
}
|
1198 |
+
|
1199 |
+
/* The "arcfour128" algorithm is the RC4 cipher, as described in
|
1200 |
+
[SCHNEIER], using a 128-bit key. The first 1536 bytes of keystream
|
1201 |
+
generated by the cipher MUST be discarded, and the first byte of the
|
1202 |
+
first encrypted packet MUST be encrypted using the 1537th byte of
|
1203 |
+
keystream.
|
1204 |
+
|
1205 |
+
-- http://tools.ietf.org/html/rfc4345#section-4 */
|
1206 |
+
if ($encrypt == 'arcfour128' || $encrypt == 'arcfour256') {
|
1207 |
+
$this->encrypt->encrypt(str_repeat("\0", 1536));
|
1208 |
+
}
|
1209 |
+
if ($decrypt == 'arcfour128' || $decrypt == 'arcfour256') {
|
1210 |
+
$this->decrypt->decrypt(str_repeat("\0", 1536));
|
1211 |
+
}
|
1212 |
+
|
1213 |
+
for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_client_to_server); $i++);
|
1214 |
+
if ($i == count($mac_algorithms)) {
|
1215 |
+
user_error('No compatible client to server message authentication algorithms found', E_USER_NOTICE);
|
1216 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
1217 |
+
}
|
1218 |
+
|
1219 |
+
$createKeyLength = 0; // ie. $mac_algorithms[$i] == 'none'
|
1220 |
+
switch ($mac_algorithms[$i]) {
|
1221 |
+
case 'hmac-sha1':
|
1222 |
+
$this->hmac_create = new Crypt_Hash('sha1');
|
1223 |
+
$createKeyLength = 20;
|
1224 |
+
break;
|
1225 |
+
case 'hmac-sha1-96':
|
1226 |
+
$this->hmac_create = new Crypt_Hash('sha1-96');
|
1227 |
+
$createKeyLength = 20;
|
1228 |
+
break;
|
1229 |
+
case 'hmac-md5':
|
1230 |
+
$this->hmac_create = new Crypt_Hash('md5');
|
1231 |
+
$createKeyLength = 16;
|
1232 |
+
break;
|
1233 |
+
case 'hmac-md5-96':
|
1234 |
+
$this->hmac_create = new Crypt_Hash('md5-96');
|
1235 |
+
$createKeyLength = 16;
|
1236 |
+
}
|
1237 |
+
|
1238 |
+
for ($i = 0; $i < count($mac_algorithms) && !in_array($mac_algorithms[$i], $this->mac_algorithms_server_to_client); $i++);
|
1239 |
+
if ($i == count($mac_algorithms)) {
|
1240 |
+
user_error('No compatible server to client message authentication algorithms found', E_USER_NOTICE);
|
1241 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
1242 |
+
}
|
1243 |
+
|
1244 |
+
$checkKeyLength = 0;
|
1245 |
+
$this->hmac_size = 0;
|
1246 |
+
switch ($mac_algorithms[$i]) {
|
1247 |
+
case 'hmac-sha1':
|
1248 |
+
$this->hmac_check = new Crypt_Hash('sha1');
|
1249 |
+
$checkKeyLength = 20;
|
1250 |
+
$this->hmac_size = 20;
|
1251 |
+
break;
|
1252 |
+
case 'hmac-sha1-96':
|
1253 |
+
$this->hmac_check = new Crypt_Hash('sha1-96');
|
1254 |
+
$checkKeyLength = 20;
|
1255 |
+
$this->hmac_size = 12;
|
1256 |
+
break;
|
1257 |
+
case 'hmac-md5':
|
1258 |
+
$this->hmac_check = new Crypt_Hash('md5');
|
1259 |
+
$checkKeyLength = 16;
|
1260 |
+
$this->hmac_size = 16;
|
1261 |
+
break;
|
1262 |
+
case 'hmac-md5-96':
|
1263 |
+
$this->hmac_check = new Crypt_Hash('md5-96');
|
1264 |
+
$checkKeyLength = 16;
|
1265 |
+
$this->hmac_size = 12;
|
1266 |
+
}
|
1267 |
+
|
1268 |
+
$key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'E' . $this->session_id));
|
1269 |
+
while ($createKeyLength > strlen($key)) {
|
1270 |
+
$key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key));
|
1271 |
+
}
|
1272 |
+
$this->hmac_create->setKey(substr($key, 0, $createKeyLength));
|
1273 |
+
|
1274 |
+
$key = pack('H*', $hash($keyBytes . $this->exchange_hash . 'F' . $this->session_id));
|
1275 |
+
while ($checkKeyLength > strlen($key)) {
|
1276 |
+
$key.= pack('H*', $hash($keyBytes . $this->exchange_hash . $key));
|
1277 |
+
}
|
1278 |
+
$this->hmac_check->setKey(substr($key, 0, $checkKeyLength));
|
1279 |
+
|
1280 |
+
for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_server_to_client); $i++);
|
1281 |
+
if ($i == count($compression_algorithms)) {
|
1282 |
+
user_error('No compatible server to client compression algorithms found', E_USER_NOTICE);
|
1283 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
1284 |
+
}
|
1285 |
+
$this->decompress = $compression_algorithms[$i] == 'zlib';
|
1286 |
+
|
1287 |
+
for ($i = 0; $i < count($compression_algorithms) && !in_array($compression_algorithms[$i], $this->compression_algorithms_client_to_server); $i++);
|
1288 |
+
if ($i == count($compression_algorithms)) {
|
1289 |
+
user_error('No compatible client to server compression algorithms found', E_USER_NOTICE);
|
1290 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
1291 |
+
}
|
1292 |
+
$this->compress = $compression_algorithms[$i] == 'zlib';
|
1293 |
+
|
1294 |
+
return true;
|
1295 |
+
}
|
1296 |
+
|
1297 |
+
/**
|
1298 |
+
* Login
|
1299 |
+
*
|
1300 |
+
* The $password parameter can be a plaintext password or a Crypt_RSA object.
|
1301 |
+
*
|
1302 |
+
* @param String $username
|
1303 |
+
* @param optional String $password
|
1304 |
+
* @return Boolean
|
1305 |
+
* @access public
|
1306 |
+
* @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
|
1307 |
+
* by sending dummy SSH_MSG_IGNORE messages.
|
1308 |
+
*/
|
1309 |
+
function login($username, $password = '')
|
1310 |
+
{
|
1311 |
+
if (!($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR)) {
|
1312 |
+
return false;
|
1313 |
+
}
|
1314 |
+
|
1315 |
+
$packet = pack('CNa*',
|
1316 |
+
NET_SSH2_MSG_SERVICE_REQUEST, strlen('ssh-userauth'), 'ssh-userauth'
|
1317 |
+
);
|
1318 |
+
|
1319 |
+
if (!$this->_send_binary_packet($packet)) {
|
1320 |
+
return false;
|
1321 |
+
}
|
1322 |
+
|
1323 |
+
$response = $this->_get_binary_packet();
|
1324 |
+
if ($response === false) {
|
1325 |
+
user_error('Connection closed by server', E_USER_NOTICE);
|
1326 |
+
return false;
|
1327 |
+
}
|
1328 |
+
|
1329 |
+
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
1330 |
+
|
1331 |
+
if ($type != NET_SSH2_MSG_SERVICE_ACCEPT) {
|
1332 |
+
user_error('Expected SSH_MSG_SERVICE_ACCEPT', E_USER_NOTICE);
|
1333 |
+
return false;
|
1334 |
+
}
|
1335 |
+
|
1336 |
+
// although PHP5's get_class() preserves the case, PHP4's does not
|
1337 |
+
if (is_object($password) && strtolower(get_class($password)) == 'crypt_rsa') {
|
1338 |
+
return $this->_privatekey_login($username, $password);
|
1339 |
+
}
|
1340 |
+
|
1341 |
+
$utf8_password = utf8_encode($password);
|
1342 |
+
$packet = pack('CNa*Na*Na*CNa*',
|
1343 |
+
NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
|
1344 |
+
strlen('password'), 'password', 0, strlen($utf8_password), $utf8_password
|
1345 |
+
);
|
1346 |
+
|
1347 |
+
if (!$this->_send_binary_packet($packet)) {
|
1348 |
+
return false;
|
1349 |
+
}
|
1350 |
+
|
1351 |
+
// remove the username and password from the last logged packet
|
1352 |
+
if (defined('NET_SSH2_LOGGING') && NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
|
1353 |
+
$packet = pack('CNa*Na*Na*CNa*',
|
1354 |
+
NET_SSH2_MSG_USERAUTH_REQUEST, strlen('username'), 'username', strlen('ssh-connection'), 'ssh-connection',
|
1355 |
+
strlen('password'), 'password', 0, strlen('password'), 'password'
|
1356 |
+
);
|
1357 |
+
$this->message_log[count($this->message_log) - 1] = $packet;
|
1358 |
+
}
|
1359 |
+
|
1360 |
+
$response = $this->_get_binary_packet();
|
1361 |
+
if ($response === false) {
|
1362 |
+
user_error('Connection closed by server', E_USER_NOTICE);
|
1363 |
+
return false;
|
1364 |
+
}
|
1365 |
+
|
1366 |
+
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
1367 |
+
|
1368 |
+
switch ($type) {
|
1369 |
+
case NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ: // in theory, the password can be changed
|
1370 |
+
if (defined('NET_SSH2_LOGGING')) {
|
1371 |
+
$this->message_number_log[count($this->message_number_log) - 1] = 'NET_SSH2_MSG_USERAUTH_PASSWD_CHANGEREQ';
|
1372 |
+
}
|
1373 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1374 |
+
$this->errors[] = 'SSH_MSG_USERAUTH_PASSWD_CHANGEREQ: ' . utf8_decode($this->_string_shift($response, $length));
|
1375 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
|
1376 |
+
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
1377 |
+
// can we use keyboard-interactive authentication? if not then either the login is bad or the server employees
|
1378 |
+
// multi-factor authentication
|
1379 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1380 |
+
$auth_methods = explode(',', $this->_string_shift($response, $length));
|
1381 |
+
if (in_array('keyboard-interactive', $auth_methods)) {
|
1382 |
+
if ($this->_keyboard_interactive_login($username, $password)) {
|
1383 |
+
$this->bitmap |= NET_SSH2_MASK_LOGIN;
|
1384 |
+
return true;
|
1385 |
+
}
|
1386 |
+
return false;
|
1387 |
+
}
|
1388 |
+
return false;
|
1389 |
+
case NET_SSH2_MSG_USERAUTH_SUCCESS:
|
1390 |
+
$this->bitmap |= NET_SSH2_MASK_LOGIN;
|
1391 |
+
return true;
|
1392 |
+
}
|
1393 |
+
|
1394 |
+
return false;
|
1395 |
+
}
|
1396 |
+
|
1397 |
+
/**
|
1398 |
+
* Login via keyboard-interactive authentication
|
1399 |
+
*
|
1400 |
+
* See {@link http://tools.ietf.org/html/rfc4256 RFC4256} for details. This is not a full-featured keyboard-interactive authenticator.
|
1401 |
+
*
|
1402 |
+
* @param String $username
|
1403 |
+
* @param String $password
|
1404 |
+
* @return Boolean
|
1405 |
+
* @access private
|
1406 |
+
*/
|
1407 |
+
function _keyboard_interactive_login($username, $password)
|
1408 |
+
{
|
1409 |
+
$packet = pack('CNa*Na*Na*Na*Na*',
|
1410 |
+
NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
|
1411 |
+
strlen('keyboard-interactive'), 'keyboard-interactive', 0, '', 0, ''
|
1412 |
+
);
|
1413 |
+
|
1414 |
+
if (!$this->_send_binary_packet($packet)) {
|
1415 |
+
return false;
|
1416 |
+
}
|
1417 |
+
|
1418 |
+
return $this->_keyboard_interactive_process($password);
|
1419 |
+
}
|
1420 |
+
|
1421 |
+
/**
|
1422 |
+
* Handle the keyboard-interactive requests / responses.
|
1423 |
+
*
|
1424 |
+
* @param String $responses...
|
1425 |
+
* @return Boolean
|
1426 |
+
* @access private
|
1427 |
+
*/
|
1428 |
+
function _keyboard_interactive_process()
|
1429 |
+
{
|
1430 |
+
$responses = func_get_args();
|
1431 |
+
|
1432 |
+
$response = $this->_get_binary_packet();
|
1433 |
+
if ($response === false) {
|
1434 |
+
user_error('Connection closed by server', E_USER_NOTICE);
|
1435 |
+
return false;
|
1436 |
+
}
|
1437 |
+
|
1438 |
+
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
1439 |
+
|
1440 |
+
switch ($type) {
|
1441 |
+
case NET_SSH2_MSG_USERAUTH_INFO_REQUEST:
|
1442 |
+
// see http://tools.ietf.org/html/rfc4256#section-3.2
|
1443 |
+
if (defined('NET_SSH2_LOGGING')) {
|
1444 |
+
$this->message_number_log[count($this->message_number_log) - 1] = str_replace(
|
1445 |
+
'UNKNOWN',
|
1446 |
+
'NET_SSH2_MSG_USERAUTH_INFO_REQUEST',
|
1447 |
+
$this->message_number_log[count($this->message_number_log) - 1]
|
1448 |
+
);
|
1449 |
+
}
|
1450 |
+
|
1451 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1452 |
+
$this->_string_shift($response, $length); // name; may be empty
|
1453 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1454 |
+
$this->_string_shift($response, $length); // instruction; may be empty
|
1455 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1456 |
+
$this->_string_shift($response, $length); // language tag; may be empty
|
1457 |
+
extract(unpack('Nnum_prompts', $this->_string_shift($response, 4)));
|
1458 |
+
/*
|
1459 |
+
for ($i = 0; $i < $num_prompts; $i++) {
|
1460 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1461 |
+
// prompt - ie. "Password: "; must not be empty
|
1462 |
+
$this->_string_shift($response, $length);
|
1463 |
+
$echo = $this->_string_shift($response) != chr(0);
|
1464 |
+
}
|
1465 |
+
*/
|
1466 |
+
|
1467 |
+
/*
|
1468 |
+
After obtaining the requested information from the user, the client
|
1469 |
+
MUST respond with an SSH_MSG_USERAUTH_INFO_RESPONSE message.
|
1470 |
+
*/
|
1471 |
+
// see http://tools.ietf.org/html/rfc4256#section-3.4
|
1472 |
+
$packet = $logged = pack('CN', NET_SSH2_MSG_USERAUTH_INFO_RESPONSE, count($responses));
|
1473 |
+
for ($i = 0; $i < count($responses); $i++) {
|
1474 |
+
$packet.= pack('Na*', strlen($responses[$i]), $responses[$i]);
|
1475 |
+
$logged.= pack('Na*', strlen('dummy-answer'), 'dummy-answer');
|
1476 |
+
}
|
1477 |
+
|
1478 |
+
if (!$this->_send_binary_packet($packet)) {
|
1479 |
+
return false;
|
1480 |
+
}
|
1481 |
+
|
1482 |
+
if (defined('NET_SSH2_LOGGING')) {
|
1483 |
+
$this->message_number_log[count($this->message_number_log) - 1] = str_replace(
|
1484 |
+
'UNKNOWN',
|
1485 |
+
'NET_SSH2_MSG_USERAUTH_INFO_RESPONSE',
|
1486 |
+
$this->message_number_log[count($this->message_number_log) - 1]
|
1487 |
+
);
|
1488 |
+
$this->message_log[count($this->message_log) - 1] = $logged;
|
1489 |
+
}
|
1490 |
+
|
1491 |
+
/*
|
1492 |
+
After receiving the response, the server MUST send either an
|
1493 |
+
SSH_MSG_USERAUTH_SUCCESS, SSH_MSG_USERAUTH_FAILURE, or another
|
1494 |
+
SSH_MSG_USERAUTH_INFO_REQUEST message.
|
1495 |
+
*/
|
1496 |
+
// maybe phpseclib should force close the connection after x request / responses? unless something like that is done
|
1497 |
+
// there could be an infinite loop of request / responses.
|
1498 |
+
return $this->_keyboard_interactive_process();
|
1499 |
+
case NET_SSH2_MSG_USERAUTH_SUCCESS:
|
1500 |
+
return true;
|
1501 |
+
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
1502 |
+
return false;
|
1503 |
+
}
|
1504 |
+
|
1505 |
+
return false;
|
1506 |
+
}
|
1507 |
+
|
1508 |
+
/**
|
1509 |
+
* Login with an RSA private key
|
1510 |
+
*
|
1511 |
+
* @param String $username
|
1512 |
+
* @param Crypt_RSA $password
|
1513 |
+
* @return Boolean
|
1514 |
+
* @access private
|
1515 |
+
* @internal It might be worthwhile, at some point, to protect against {@link http://tools.ietf.org/html/rfc4251#section-9.3.9 traffic analysis}
|
1516 |
+
* by sending dummy SSH_MSG_IGNORE messages.
|
1517 |
+
*/
|
1518 |
+
function _privatekey_login($username, $privatekey)
|
1519 |
+
{
|
1520 |
+
// see http://tools.ietf.org/html/rfc4253#page-15
|
1521 |
+
$publickey = $privatekey->getPublicKey(CRYPT_RSA_PUBLIC_FORMAT_RAW);
|
1522 |
+
if ($publickey === false) {
|
1523 |
+
return false;
|
1524 |
+
}
|
1525 |
+
|
1526 |
+
$publickey = array(
|
1527 |
+
'e' => $publickey['e']->toBytes(true),
|
1528 |
+
'n' => $publickey['n']->toBytes(true)
|
1529 |
+
);
|
1530 |
+
$publickey = pack('Na*Na*Na*',
|
1531 |
+
strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey['e']), $publickey['e'], strlen($publickey['n']), $publickey['n']
|
1532 |
+
);
|
1533 |
+
|
1534 |
+
$part1 = pack('CNa*Na*Na*',
|
1535 |
+
NET_SSH2_MSG_USERAUTH_REQUEST, strlen($username), $username, strlen('ssh-connection'), 'ssh-connection',
|
1536 |
+
strlen('publickey'), 'publickey'
|
1537 |
+
);
|
1538 |
+
$part2 = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($publickey), $publickey);
|
1539 |
+
|
1540 |
+
$packet = $part1 . chr(0) . $part2;
|
1541 |
+
if (!$this->_send_binary_packet($packet)) {
|
1542 |
+
return false;
|
1543 |
+
}
|
1544 |
+
|
1545 |
+
$response = $this->_get_binary_packet();
|
1546 |
+
if ($response === false) {
|
1547 |
+
user_error('Connection closed by server', E_USER_NOTICE);
|
1548 |
+
return false;
|
1549 |
+
}
|
1550 |
+
|
1551 |
+
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
1552 |
+
|
1553 |
+
switch ($type) {
|
1554 |
+
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
1555 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
1556 |
+
$this->errors[] = 'SSH_MSG_USERAUTH_FAILURE: ' . $this->_string_shift($response, $length);
|
1557 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_AUTH_CANCELLED_BY_USER);
|
1558 |
+
case NET_SSH2_MSG_USERAUTH_PK_OK:
|
1559 |
+
// we'll just take it on faith that the public key blob and the public key algorithm name are as
|
1560 |
+
// they should be
|
1561 |
+
if (defined('NET_SSH2_LOGGING')) {
|
1562 |
+
$this->message_number_log[count($this->message_number_log) - 1] = str_replace(
|
1563 |
+
'UNKNOWN',
|
1564 |
+
'NET_SSH2_MSG_USERAUTH_PK_OK',
|
1565 |
+
$this->message_number_log[count($this->message_number_log) - 1]
|
1566 |
+
);
|
1567 |
+
}
|
1568 |
+
}
|
1569 |
+
|
1570 |
+
$packet = $part1 . chr(1) . $part2;
|
1571 |
+
$privatekey->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
|
1572 |
+
$signature = $privatekey->sign(pack('Na*a*', strlen($this->session_id), $this->session_id, $packet));
|
1573 |
+
$signature = pack('Na*Na*', strlen('ssh-rsa'), 'ssh-rsa', strlen($signature), $signature);
|
1574 |
+
$packet.= pack('Na*', strlen($signature), $signature);
|
1575 |
+
|
1576 |
+
if (!$this->_send_binary_packet($packet)) {
|
1577 |
+
return false;
|
1578 |
+
}
|
1579 |
+
|
1580 |
+
$response = $this->_get_binary_packet();
|
1581 |
+
if ($response === false) {
|
1582 |
+
user_error('Connection closed by server', E_USER_NOTICE);
|
1583 |
+
return false;
|
1584 |
+
}
|
1585 |
+
|
1586 |
+
extract(unpack('Ctype', $this->_string_shift($response, 1)));
|
1587 |
+
|
1588 |
+
switch ($type) {
|
1589 |
+
case NET_SSH2_MSG_USERAUTH_FAILURE:
|
1590 |
+
// either the login is bad or the server employees multi-factor authentication
|
1591 |
+
return false;
|
1592 |
+
case NET_SSH2_MSG_USERAUTH_SUCCESS:
|
1593 |
+
$this->bitmap |= NET_SSH2_MASK_LOGIN;
|
1594 |
+
return true;
|
1595 |
+
}
|
1596 |
+
|
1597 |
+
return false;
|
1598 |
+
}
|
1599 |
+
|
1600 |
+
/**
|
1601 |
+
* Execute Command
|
1602 |
+
*
|
1603 |
+
* If $block is set to false then Net_SSH2::_get_channel_packet(NET_SSH2_CHANNEL_EXEC) will need to be called manually.
|
1604 |
+
* In all likelihood, this is not a feature you want to be taking advantage of.
|
1605 |
+
*
|
1606 |
+
* @param String $command
|
1607 |
+
* @param optional Boolean $block
|
1608 |
+
* @return String
|
1609 |
+
* @access public
|
1610 |
+
*/
|
1611 |
+
function exec($command, $block = true)
|
1612 |
+
{
|
1613 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
1614 |
+
return false;
|
1615 |
+
}
|
1616 |
+
|
1617 |
+
// RFC4254 defines the (client) window size as "bytes the other party can send before it must wait for the window to
|
1618 |
+
// be adjusted". 0x7FFFFFFF is, at 4GB, the max size. technically, it should probably be decremented, but,
|
1619 |
+
// honestly, if you're transfering more than 4GB, you probably shouldn't be using phpseclib, anyway.
|
1620 |
+
// see http://tools.ietf.org/html/rfc4254#section-5.2 for more info
|
1621 |
+
$this->window_size_client_to_server[NET_SSH2_CHANNEL_EXEC] = 0x7FFFFFFF;
|
1622 |
+
// 0x8000 is the maximum max packet size, per http://tools.ietf.org/html/rfc4253#section-6.1, although since PuTTy
|
1623 |
+
// uses 0x4000, that's what will be used here, as well.
|
1624 |
+
$packet_size = 0x4000;
|
1625 |
+
|
1626 |
+
$packet = pack('CNa*N3',
|
1627 |
+
NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_EXEC, $this->window_size_client_to_server[NET_SSH2_CHANNEL_EXEC], $packet_size);
|
1628 |
+
|
1629 |
+
if (!$this->_send_binary_packet($packet)) {
|
1630 |
+
return false;
|
1631 |
+
}
|
1632 |
+
|
1633 |
+
$this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_OPEN;
|
1634 |
+
|
1635 |
+
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC);
|
1636 |
+
if ($response === false) {
|
1637 |
+
return false;
|
1638 |
+
}
|
1639 |
+
|
1640 |
+
// sending a pty-req SSH_MSG_CHANNEL_REQUEST message is unnecessary and, in fact, in most cases, slows things
|
1641 |
+
// down. the one place where it might be desirable is if you're doing something like Net_SSH2::exec('ping localhost &').
|
1642 |
+
// with a pty-req SSH_MSG_CHANNEL_REQUEST, exec() will return immediately and the ping process will then
|
1643 |
+
// then immediately terminate. without such a request exec() will loop indefinitely. the ping process won't end but
|
1644 |
+
// neither will your script.
|
1645 |
+
|
1646 |
+
// although, in theory, the size of SSH_MSG_CHANNEL_REQUEST could exceed the maximum packet size established by
|
1647 |
+
// SSH_MSG_CHANNEL_OPEN_CONFIRMATION, RFC4254#section-5.1 states that the "maximum packet size" refers to the
|
1648 |
+
// "maximum size of an individual data packet". ie. SSH_MSG_CHANNEL_DATA. RFC4254#section-5.2 corroborates.
|
1649 |
+
$packet = pack('CNNa*CNa*',
|
1650 |
+
NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_EXEC], strlen('exec'), 'exec', 1, strlen($command), $command);
|
1651 |
+
if (!$this->_send_binary_packet($packet)) {
|
1652 |
+
return false;
|
1653 |
+
}
|
1654 |
+
|
1655 |
+
$this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_REQUEST;
|
1656 |
+
|
1657 |
+
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC);
|
1658 |
+
if ($response === false) {
|
1659 |
+
return false;
|
1660 |
+
}
|
1661 |
+
|
1662 |
+
$this->channel_status[NET_SSH2_CHANNEL_EXEC] = NET_SSH2_MSG_CHANNEL_DATA;
|
1663 |
+
|
1664 |
+
if (!$block) {
|
1665 |
+
return true;
|
1666 |
+
}
|
1667 |
+
|
1668 |
+
$output = '';
|
1669 |
+
while (true) {
|
1670 |
+
$temp = $this->_get_channel_packet(NET_SSH2_CHANNEL_EXEC);
|
1671 |
+
switch (true) {
|
1672 |
+
case $temp === true:
|
1673 |
+
return $output;
|
1674 |
+
case $temp === false:
|
1675 |
+
return false;
|
1676 |
+
default:
|
1677 |
+
$output.= $temp;
|
1678 |
+
}
|
1679 |
+
}
|
1680 |
+
}
|
1681 |
+
|
1682 |
+
/**
|
1683 |
+
* Creates an interactive shell
|
1684 |
+
*
|
1685 |
+
* @see Net_SSH2::read()
|
1686 |
+
* @see Net_SSH2::write()
|
1687 |
+
* @return Boolean
|
1688 |
+
* @access private
|
1689 |
+
*/
|
1690 |
+
function _initShell()
|
1691 |
+
{
|
1692 |
+
$this->window_size_client_to_server[NET_SSH2_CHANNEL_SHELL] = 0x7FFFFFFF;
|
1693 |
+
$packet_size = 0x4000;
|
1694 |
+
|
1695 |
+
$packet = pack('CNa*N3',
|
1696 |
+
NET_SSH2_MSG_CHANNEL_OPEN, strlen('session'), 'session', NET_SSH2_CHANNEL_SHELL, $this->window_size_client_to_server[NET_SSH2_CHANNEL_SHELL], $packet_size);
|
1697 |
+
|
1698 |
+
if (!$this->_send_binary_packet($packet)) {
|
1699 |
+
return false;
|
1700 |
+
}
|
1701 |
+
|
1702 |
+
$this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_OPEN;
|
1703 |
+
|
1704 |
+
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL);
|
1705 |
+
if ($response === false) {
|
1706 |
+
return false;
|
1707 |
+
}
|
1708 |
+
|
1709 |
+
$terminal_modes = pack('C', NET_SSH2_TTY_OP_END);
|
1710 |
+
$packet = pack('CNNa*CNa*N5a*',
|
1711 |
+
NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('pty-req'), 'pty-req', 1, strlen('vt100'), 'vt100',
|
1712 |
+
80, 24, 0, 0, strlen($terminal_modes), $terminal_modes);
|
1713 |
+
|
1714 |
+
if (!$this->_send_binary_packet($packet)) {
|
1715 |
+
return false;
|
1716 |
+
}
|
1717 |
+
|
1718 |
+
|
1719 |
+
$response = $this->_get_binary_packet();
|
1720 |
+
if ($response === false) {
|
1721 |
+
user_error('Connection closed by server', E_USER_NOTICE);
|
1722 |
+
return false;
|
1723 |
+
}
|
1724 |
+
|
1725 |
+
list(, $type) = unpack('C', $this->_string_shift($response, 1));
|
1726 |
+
|
1727 |
+
switch ($type) {
|
1728 |
+
case NET_SSH2_MSG_CHANNEL_SUCCESS:
|
1729 |
+
break;
|
1730 |
+
case NET_SSH2_MSG_CHANNEL_FAILURE:
|
1731 |
+
default:
|
1732 |
+
user_error('Unable to request pseudo-terminal', E_USER_NOTICE);
|
1733 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
1734 |
+
}
|
1735 |
+
|
1736 |
+
$packet = pack('CNNa*C',
|
1737 |
+
NET_SSH2_MSG_CHANNEL_REQUEST, $this->server_channels[NET_SSH2_CHANNEL_SHELL], strlen('shell'), 'shell', 1);
|
1738 |
+
if (!$this->_send_binary_packet($packet)) {
|
1739 |
+
return false;
|
1740 |
+
}
|
1741 |
+
|
1742 |
+
$this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_REQUEST;
|
1743 |
+
|
1744 |
+
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL);
|
1745 |
+
if ($response === false) {
|
1746 |
+
return false;
|
1747 |
+
}
|
1748 |
+
|
1749 |
+
$this->channel_status[NET_SSH2_CHANNEL_SHELL] = NET_SSH2_MSG_CHANNEL_DATA;
|
1750 |
+
|
1751 |
+
$this->bitmap |= NET_SSH2_MASK_SHELL;
|
1752 |
+
|
1753 |
+
return true;
|
1754 |
+
}
|
1755 |
+
|
1756 |
+
/**
|
1757 |
+
* Returns the output of an interactive shell
|
1758 |
+
*
|
1759 |
+
* Returns when there's a match for $expect, which can take the form of a string literal or,
|
1760 |
+
* if $mode == NET_SSH2_READ_REGEX, a regular expression.
|
1761 |
+
*
|
1762 |
+
* @see Net_SSH2::read()
|
1763 |
+
* @param String $expect
|
1764 |
+
* @param Integer $mode
|
1765 |
+
* @return String
|
1766 |
+
* @access public
|
1767 |
+
*/
|
1768 |
+
function read($expect, $mode = NET_SSH2_READ_SIMPLE)
|
1769 |
+
{
|
1770 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
1771 |
+
user_error('Operation disallowed prior to login()', E_USER_NOTICE);
|
1772 |
+
return false;
|
1773 |
+
}
|
1774 |
+
|
1775 |
+
if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) {
|
1776 |
+
user_error('Unable to initiate an interactive shell session', E_USER_NOTICE);
|
1777 |
+
return false;
|
1778 |
+
}
|
1779 |
+
|
1780 |
+
$match = $expect;
|
1781 |
+
while (true) {
|
1782 |
+
if ($mode == NET_SSH2_READ_REGEX) {
|
1783 |
+
preg_match($expect, $this->interactiveBuffer, $matches);
|
1784 |
+
$match = $matches[0];
|
1785 |
+
}
|
1786 |
+
$pos = strpos($this->interactiveBuffer, $match);
|
1787 |
+
if ($pos !== false) {
|
1788 |
+
return $this->_string_shift($this->interactiveBuffer, $pos + strlen($match));
|
1789 |
+
}
|
1790 |
+
$response = $this->_get_channel_packet(NET_SSH2_CHANNEL_SHELL);
|
1791 |
+
|
1792 |
+
$this->interactiveBuffer.= $response;
|
1793 |
+
}
|
1794 |
+
}
|
1795 |
+
|
1796 |
+
/**
|
1797 |
+
* Inputs a command into an interactive shell.
|
1798 |
+
*
|
1799 |
+
* @see Net_SSH1::interactiveWrite()
|
1800 |
+
* @param String $cmd
|
1801 |
+
* @return Boolean
|
1802 |
+
* @access public
|
1803 |
+
*/
|
1804 |
+
function write($cmd)
|
1805 |
+
{
|
1806 |
+
if (!($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
1807 |
+
user_error('Operation disallowed prior to login()', E_USER_NOTICE);
|
1808 |
+
return false;
|
1809 |
+
}
|
1810 |
+
|
1811 |
+
if (!($this->bitmap & NET_SSH2_MASK_SHELL) && !$this->_initShell()) {
|
1812 |
+
user_error('Unable to initiate an interactive shell session', E_USER_NOTICE);
|
1813 |
+
return false;
|
1814 |
+
}
|
1815 |
+
|
1816 |
+
return $this->_send_channel_packet(NET_SSH2_CHANNEL_SHELL, $cmd);
|
1817 |
+
}
|
1818 |
+
|
1819 |
+
/**
|
1820 |
+
* Disconnect
|
1821 |
+
*
|
1822 |
+
* @access public
|
1823 |
+
*/
|
1824 |
+
function disconnect()
|
1825 |
+
{
|
1826 |
+
$this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
1827 |
+
}
|
1828 |
+
|
1829 |
+
/**
|
1830 |
+
* Destructor.
|
1831 |
+
*
|
1832 |
+
* Will be called, automatically, if you're supporting just PHP5. If you're supporting PHP4, you'll need to call
|
1833 |
+
* disconnect().
|
1834 |
+
*
|
1835 |
+
* @access public
|
1836 |
+
*/
|
1837 |
+
function __destruct()
|
1838 |
+
{
|
1839 |
+
$this->disconnect();
|
1840 |
+
}
|
1841 |
+
|
1842 |
+
/**
|
1843 |
+
* Gets Binary Packets
|
1844 |
+
*
|
1845 |
+
* See '6. Binary Packet Protocol' of rfc4253 for more info.
|
1846 |
+
*
|
1847 |
+
* @see Net_SSH2::_send_binary_packet()
|
1848 |
+
* @return String
|
1849 |
+
* @access private
|
1850 |
+
*/
|
1851 |
+
function _get_binary_packet()
|
1852 |
+
{
|
1853 |
+
if (feof($this->fsock)) {
|
1854 |
+
user_error('Connection closed prematurely', E_USER_NOTICE);
|
1855 |
+
return false;
|
1856 |
+
}
|
1857 |
+
|
1858 |
+
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
|
1859 |
+
$raw = fread($this->fsock, $this->decrypt_block_size);
|
1860 |
+
$stop = strtok(microtime(), ' ') + strtok('');
|
1861 |
+
|
1862 |
+
if (empty($raw)) {
|
1863 |
+
return '';
|
1864 |
+
}
|
1865 |
+
|
1866 |
+
if ($this->decrypt !== false) {
|
1867 |
+
$raw = $this->decrypt->decrypt($raw);
|
1868 |
+
}
|
1869 |
+
|
1870 |
+
extract(unpack('Npacket_length/Cpadding_length', $this->_string_shift($raw, 5)));
|
1871 |
+
|
1872 |
+
$remaining_length = $packet_length + 4 - $this->decrypt_block_size;
|
1873 |
+
$buffer = '';
|
1874 |
+
while ($remaining_length > 0) {
|
1875 |
+
$temp = fread($this->fsock, $remaining_length);
|
1876 |
+
$buffer.= $temp;
|
1877 |
+
$remaining_length-= strlen($temp);
|
1878 |
+
}
|
1879 |
+
if (!empty($buffer)) {
|
1880 |
+
$raw.= $this->decrypt !== false ? $this->decrypt->decrypt($buffer) : $buffer;
|
1881 |
+
$buffer = $temp = '';
|
1882 |
+
}
|
1883 |
+
|
1884 |
+
$payload = $this->_string_shift($raw, $packet_length - $padding_length - 1);
|
1885 |
+
$padding = $this->_string_shift($raw, $padding_length); // should leave $raw empty
|
1886 |
+
|
1887 |
+
if ($this->hmac_check !== false) {
|
1888 |
+
$hmac = fread($this->fsock, $this->hmac_size);
|
1889 |
+
if ($hmac != $this->hmac_check->hash(pack('NNCa*', $this->get_seq_no, $packet_length, $padding_length, $payload . $padding))) {
|
1890 |
+
user_error('Invalid HMAC', E_USER_NOTICE);
|
1891 |
+
return false;
|
1892 |
+
}
|
1893 |
+
}
|
1894 |
+
|
1895 |
+
//if ($this->decompress) {
|
1896 |
+
// $payload = gzinflate(substr($payload, 2));
|
1897 |
+
//}
|
1898 |
+
|
1899 |
+
$this->get_seq_no++;
|
1900 |
+
|
1901 |
+
if (defined('NET_SSH2_LOGGING')) {
|
1902 |
+
$temp = isset($this->message_numbers[ord($payload[0])]) ? $this->message_numbers[ord($payload[0])] : 'UNKNOWN (' . ord($payload[0]) . ')';
|
1903 |
+
$this->message_number_log[] = '<- ' . $temp .
|
1904 |
+
' (' . round($stop - $start, 4) . 's)';
|
1905 |
+
if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
|
1906 |
+
$this->message_log[] = substr($payload, 1);
|
1907 |
+
}
|
1908 |
+
}
|
1909 |
+
|
1910 |
+
return $this->_filter($payload);
|
1911 |
+
}
|
1912 |
+
|
1913 |
+
/**
|
1914 |
+
* Filter Binary Packets
|
1915 |
+
*
|
1916 |
+
* Because some binary packets need to be ignored...
|
1917 |
+
*
|
1918 |
+
* @see Net_SSH2::_get_binary_packet()
|
1919 |
+
* @return String
|
1920 |
+
* @access private
|
1921 |
+
*/
|
1922 |
+
function _filter($payload)
|
1923 |
+
{
|
1924 |
+
switch (ord($payload[0])) {
|
1925 |
+
case NET_SSH2_MSG_DISCONNECT:
|
1926 |
+
$this->_string_shift($payload, 1);
|
1927 |
+
extract(unpack('Nreason_code/Nlength', $this->_string_shift($payload, 8)));
|
1928 |
+
$this->errors[] = 'SSH_MSG_DISCONNECT: ' . $this->disconnect_reasons[$reason_code] . "\r\n" . utf8_decode($this->_string_shift($payload, $length));
|
1929 |
+
$this->bitmask = 0;
|
1930 |
+
return false;
|
1931 |
+
case NET_SSH2_MSG_IGNORE:
|
1932 |
+
$payload = $this->_get_binary_packet();
|
1933 |
+
break;
|
1934 |
+
case NET_SSH2_MSG_DEBUG:
|
1935 |
+
$this->_string_shift($payload, 2);
|
1936 |
+
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
|
1937 |
+
$this->errors[] = 'SSH_MSG_DEBUG: ' . utf8_decode($this->_string_shift($payload, $length));
|
1938 |
+
$payload = $this->_get_binary_packet();
|
1939 |
+
break;
|
1940 |
+
case NET_SSH2_MSG_UNIMPLEMENTED:
|
1941 |
+
return false;
|
1942 |
+
case NET_SSH2_MSG_KEXINIT:
|
1943 |
+
if ($this->session_id !== false) {
|
1944 |
+
if (!$this->_key_exchange($payload)) {
|
1945 |
+
$this->bitmask = 0;
|
1946 |
+
return false;
|
1947 |
+
}
|
1948 |
+
$payload = $this->_get_binary_packet();
|
1949 |
+
}
|
1950 |
+
}
|
1951 |
+
|
1952 |
+
// see http://tools.ietf.org/html/rfc4252#section-5.4; only called when the encryption has been activated and when we haven't already logged in
|
1953 |
+
if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && !($this->bitmap & NET_SSH2_MASK_LOGIN) && ord($payload[0]) == NET_SSH2_MSG_USERAUTH_BANNER) {
|
1954 |
+
$this->_string_shift($payload, 1);
|
1955 |
+
extract(unpack('Nlength', $this->_string_shift($payload, 4)));
|
1956 |
+
$this->errors[] = 'SSH_MSG_USERAUTH_BANNER: ' . utf8_decode($this->_string_shift($payload, $length));
|
1957 |
+
$payload = $this->_get_binary_packet();
|
1958 |
+
}
|
1959 |
+
|
1960 |
+
// only called when we've already logged in
|
1961 |
+
if (($this->bitmap & NET_SSH2_MASK_CONSTRUCTOR) && ($this->bitmap & NET_SSH2_MASK_LOGIN)) {
|
1962 |
+
switch (ord($payload[0])) {
|
1963 |
+
case NET_SSH2_MSG_GLOBAL_REQUEST: // see http://tools.ietf.org/html/rfc4254#section-4
|
1964 |
+
$this->_string_shift($payload, 1);
|
1965 |
+
extract(unpack('Nlength', $this->_string_shift($payload)));
|
1966 |
+
$this->errors[] = 'SSH_MSG_GLOBAL_REQUEST: ' . utf8_decode($this->_string_shift($payload, $length));
|
1967 |
+
|
1968 |
+
if (!$this->_send_binary_packet(pack('C', NET_SSH2_MSG_REQUEST_FAILURE))) {
|
1969 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
1970 |
+
}
|
1971 |
+
|
1972 |
+
$payload = $this->_get_binary_packet();
|
1973 |
+
break;
|
1974 |
+
case NET_SSH2_MSG_CHANNEL_OPEN: // see http://tools.ietf.org/html/rfc4254#section-5.1
|
1975 |
+
$this->_string_shift($payload, 1);
|
1976 |
+
extract(unpack('N', $this->_string_shift($payload, 4)));
|
1977 |
+
$this->errors[] = 'SSH_MSG_CHANNEL_OPEN: ' . utf8_decode($this->_string_shift($payload, $length));
|
1978 |
+
|
1979 |
+
$this->_string_shift($payload, 4); // skip over client channel
|
1980 |
+
extract(unpack('Nserver_channel', $this->_string_shift($payload, 4)));
|
1981 |
+
|
1982 |
+
$packet = pack('CN3a*Na*',
|
1983 |
+
NET_SSH2_MSG_REQUEST_FAILURE, $server_channel, NET_SSH2_OPEN_ADMINISTRATIVELY_PROHIBITED, 0, '', 0, '');
|
1984 |
+
|
1985 |
+
if (!$this->_send_binary_packet($packet)) {
|
1986 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
1987 |
+
}
|
1988 |
+
|
1989 |
+
$payload = $this->_get_binary_packet();
|
1990 |
+
break;
|
1991 |
+
case NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST:
|
1992 |
+
$payload = $this->_get_binary_packet();
|
1993 |
+
}
|
1994 |
+
}
|
1995 |
+
|
1996 |
+
return $payload;
|
1997 |
+
}
|
1998 |
+
|
1999 |
+
/**
|
2000 |
+
* Gets channel data
|
2001 |
+
*
|
2002 |
+
* Returns the data as a string if it's available and false if not.
|
2003 |
+
*
|
2004 |
+
* @param $client_channel
|
2005 |
+
* @return Mixed
|
2006 |
+
* @access private
|
2007 |
+
*/
|
2008 |
+
function _get_channel_packet($client_channel, $skip_extended = false)
|
2009 |
+
{
|
2010 |
+
if (!empty($this->channel_buffers[$client_channel])) {
|
2011 |
+
return array_shift($this->channel_buffers[$client_channel]);
|
2012 |
+
}
|
2013 |
+
|
2014 |
+
while (true) {
|
2015 |
+
$response = $this->_get_binary_packet();
|
2016 |
+
if ($response === false) {
|
2017 |
+
user_error('Connection closed by server', E_USER_NOTICE);
|
2018 |
+
return false;
|
2019 |
+
}
|
2020 |
+
|
2021 |
+
if (empty($response)) {
|
2022 |
+
return '';
|
2023 |
+
}
|
2024 |
+
|
2025 |
+
extract(unpack('Ctype/Nchannel', $this->_string_shift($response, 5)));
|
2026 |
+
|
2027 |
+
switch ($this->channel_status[$channel]) {
|
2028 |
+
case NET_SSH2_MSG_CHANNEL_OPEN:
|
2029 |
+
switch ($type) {
|
2030 |
+
case NET_SSH2_MSG_CHANNEL_OPEN_CONFIRMATION:
|
2031 |
+
extract(unpack('Nserver_channel', $this->_string_shift($response, 4)));
|
2032 |
+
$this->server_channels[$client_channel] = $server_channel;
|
2033 |
+
$this->_string_shift($response, 4); // skip over (server) window size
|
2034 |
+
$temp = unpack('Npacket_size_client_to_server', $this->_string_shift($response, 4));
|
2035 |
+
$this->packet_size_client_to_server[$client_channel] = $temp['packet_size_client_to_server'];
|
2036 |
+
return true;
|
2037 |
+
//case NET_SSH2_MSG_CHANNEL_OPEN_FAILURE:
|
2038 |
+
default:
|
2039 |
+
user_error('Unable to open channel', E_USER_NOTICE);
|
2040 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
2041 |
+
}
|
2042 |
+
break;
|
2043 |
+
case NET_SSH2_MSG_CHANNEL_REQUEST:
|
2044 |
+
switch ($type) {
|
2045 |
+
case NET_SSH2_MSG_CHANNEL_SUCCESS:
|
2046 |
+
return true;
|
2047 |
+
//case NET_SSH2_MSG_CHANNEL_FAILURE:
|
2048 |
+
default:
|
2049 |
+
user_error('Unable to request pseudo-terminal', E_USER_NOTICE);
|
2050 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
2051 |
+
}
|
2052 |
+
|
2053 |
+
}
|
2054 |
+
|
2055 |
+
switch ($type) {
|
2056 |
+
case NET_SSH2_MSG_CHANNEL_DATA:
|
2057 |
+
/*
|
2058 |
+
if ($client_channel == NET_SSH2_CHANNEL_EXEC) {
|
2059 |
+
// SCP requires null packets, such as this, be sent. further, in the case of the ssh.com SSH server
|
2060 |
+
// this actually seems to make things twice as fast. more to the point, the message right after
|
2061 |
+
// SSH_MSG_CHANNEL_DATA (usually SSH_MSG_IGNORE) won't block for as long as it would have otherwise.
|
2062 |
+
// in OpenSSH it slows things down but only by a couple thousandths of a second.
|
2063 |
+
$this->_send_channel_packet($client_channel, chr(0));
|
2064 |
+
}
|
2065 |
+
*/
|
2066 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
2067 |
+
$data = $this->_string_shift($response, $length);
|
2068 |
+
if ($client_channel == $channel) {
|
2069 |
+
return $data;
|
2070 |
+
}
|
2071 |
+
if (!isset($this->channel_buffers[$client_channel])) {
|
2072 |
+
$this->channel_buffers[$client_channel] = array();
|
2073 |
+
}
|
2074 |
+
$this->channel_buffers[$client_channel][] = $data;
|
2075 |
+
break;
|
2076 |
+
case NET_SSH2_MSG_CHANNEL_EXTENDED_DATA:
|
2077 |
+
if ($skip_extended) {
|
2078 |
+
break;
|
2079 |
+
}
|
2080 |
+
/*
|
2081 |
+
if ($client_channel == NET_SSH2_CHANNEL_EXEC) {
|
2082 |
+
$this->_send_channel_packet($client_channel, chr(0));
|
2083 |
+
}
|
2084 |
+
*/
|
2085 |
+
// currently, there's only one possible value for $data_type_code: NET_SSH2_EXTENDED_DATA_STDERR
|
2086 |
+
extract(unpack('Ndata_type_code/Nlength', $this->_string_shift($response, 8)));
|
2087 |
+
$data = $this->_string_shift($response, $length);
|
2088 |
+
if ($client_channel == $channel) {
|
2089 |
+
return $data;
|
2090 |
+
}
|
2091 |
+
if (!isset($this->channel_buffers[$client_channel])) {
|
2092 |
+
$this->channel_buffers[$client_channel] = array();
|
2093 |
+
}
|
2094 |
+
$this->channel_buffers[$client_channel][] = $data;
|
2095 |
+
break;
|
2096 |
+
case NET_SSH2_MSG_CHANNEL_REQUEST:
|
2097 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
2098 |
+
$value = $this->_string_shift($response, $length);
|
2099 |
+
switch ($value) {
|
2100 |
+
case 'exit-signal':
|
2101 |
+
$this->_string_shift($response, 1);
|
2102 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
2103 |
+
$this->errors[] = 'SSH_MSG_CHANNEL_REQUEST (exit-signal): ' . $this->_string_shift($response, $length);
|
2104 |
+
$this->_string_shift($response, 1);
|
2105 |
+
extract(unpack('Nlength', $this->_string_shift($response, 4)));
|
2106 |
+
if ($length) {
|
2107 |
+
$this->errors[count($this->errors)].= "\r\n" . $this->_string_shift($response, $length);
|
2108 |
+
}
|
2109 |
+
//case 'exit-status':
|
2110 |
+
default:
|
2111 |
+
// "Some systems may not implement signals, in which case they SHOULD ignore this message."
|
2112 |
+
// -- http://tools.ietf.org/html/rfc4254#section-6.9
|
2113 |
+
break;
|
2114 |
+
}
|
2115 |
+
break;
|
2116 |
+
case NET_SSH2_MSG_CHANNEL_CLOSE:
|
2117 |
+
$this->_send_binary_packet(pack('CN', NET_SSH2_MSG_CHANNEL_CLOSE, $this->server_channels[$channel]));
|
2118 |
+
return true;
|
2119 |
+
case NET_SSH2_MSG_CHANNEL_EOF:
|
2120 |
+
break;
|
2121 |
+
default:
|
2122 |
+
user_error('Error reading channel data', E_USER_NOTICE);
|
2123 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_BY_APPLICATION);
|
2124 |
+
}
|
2125 |
+
}
|
2126 |
+
}
|
2127 |
+
|
2128 |
+
/**
|
2129 |
+
* Sends Binary Packets
|
2130 |
+
*
|
2131 |
+
* See '6. Binary Packet Protocol' of rfc4253 for more info.
|
2132 |
+
*
|
2133 |
+
* @param String $data
|
2134 |
+
* @see Net_SSH2::_get_binary_packet()
|
2135 |
+
* @return Boolean
|
2136 |
+
* @access private
|
2137 |
+
*/
|
2138 |
+
function _send_binary_packet($data)
|
2139 |
+
{
|
2140 |
+
if (feof($this->fsock)) {
|
2141 |
+
user_error('Connection closed prematurely', E_USER_NOTICE);
|
2142 |
+
return false;
|
2143 |
+
}
|
2144 |
+
|
2145 |
+
//if ($this->compress) {
|
2146 |
+
// // the -4 removes the checksum:
|
2147 |
+
// // http://php.net/function.gzcompress#57710
|
2148 |
+
// $data = substr(gzcompress($data), 0, -4);
|
2149 |
+
//}
|
2150 |
+
|
2151 |
+
// 4 (packet length) + 1 (padding length) + 4 (minimal padding amount) == 9
|
2152 |
+
$packet_length = strlen($data) + 9;
|
2153 |
+
// round up to the nearest $this->encrypt_block_size
|
2154 |
+
$packet_length+= (($this->encrypt_block_size - 1) * $packet_length) % $this->encrypt_block_size;
|
2155 |
+
// subtracting strlen($data) is obvious - subtracting 5 is necessary because of packet_length and padding_length
|
2156 |
+
$padding_length = $packet_length - strlen($data) - 5;
|
2157 |
+
|
2158 |
+
$padding = '';
|
2159 |
+
for ($i = 0; $i < $padding_length; $i++) {
|
2160 |
+
$padding.= chr(crypt_random(0, 255));
|
2161 |
+
}
|
2162 |
+
|
2163 |
+
// we subtract 4 from packet_length because the packet_length field isn't supposed to include itself
|
2164 |
+
$packet = pack('NCa*', $packet_length - 4, $padding_length, $data . $padding);
|
2165 |
+
|
2166 |
+
$hmac = $this->hmac_create !== false ? $this->hmac_create->hash(pack('Na*', $this->send_seq_no, $packet)) : '';
|
2167 |
+
$this->send_seq_no++;
|
2168 |
+
|
2169 |
+
if ($this->encrypt !== false) {
|
2170 |
+
$packet = $this->encrypt->encrypt($packet);
|
2171 |
+
}
|
2172 |
+
|
2173 |
+
$packet.= $hmac;
|
2174 |
+
|
2175 |
+
$start = strtok(microtime(), ' ') + strtok(''); // http://php.net/microtime#61838
|
2176 |
+
$result = strlen($packet) == fputs($this->fsock, $packet);
|
2177 |
+
$stop = strtok(microtime(), ' ') + strtok('');
|
2178 |
+
|
2179 |
+
if (defined('NET_SSH2_LOGGING')) {
|
2180 |
+
$temp = isset($this->message_numbers[ord($data[0])]) ? $this->message_numbers[ord($data[0])] : 'UNKNOWN (' . ord($data[0]) . ')';
|
2181 |
+
$this->message_number_log[] = '-> ' . $temp .
|
2182 |
+
' (' . round($stop - $start, 4) . 's)';
|
2183 |
+
if (NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX) {
|
2184 |
+
$this->message_log[] = substr($data, 1);
|
2185 |
+
}
|
2186 |
+
}
|
2187 |
+
|
2188 |
+
return $result;
|
2189 |
+
}
|
2190 |
+
|
2191 |
+
/**
|
2192 |
+
* Sends channel data
|
2193 |
+
*
|
2194 |
+
* Spans multiple SSH_MSG_CHANNEL_DATAs if appropriate
|
2195 |
+
*
|
2196 |
+
* @param Integer $client_channel
|
2197 |
+
* @param String $data
|
2198 |
+
* @return Boolean
|
2199 |
+
* @access private
|
2200 |
+
*/
|
2201 |
+
function _send_channel_packet($client_channel, $data)
|
2202 |
+
{
|
2203 |
+
while (strlen($data) > $this->packet_size_client_to_server[$client_channel]) {
|
2204 |
+
// resize the window, if appropriate
|
2205 |
+
$this->window_size_client_to_server[$client_channel]-= $this->packet_size_client_to_server[$client_channel];
|
2206 |
+
if ($this->window_size_client_to_server[$client_channel] < 0) {
|
2207 |
+
$packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$client_channel], $this->window_size);
|
2208 |
+
if (!$this->_send_binary_packet($packet)) {
|
2209 |
+
return false;
|
2210 |
+
}
|
2211 |
+
$this->window_size_client_to_server[$client_channel]+= $this->window_size;
|
2212 |
+
}
|
2213 |
+
|
2214 |
+
$packet = pack('CN2a*',
|
2215 |
+
NET_SSH2_MSG_CHANNEL_DATA,
|
2216 |
+
$this->server_channels[$client_channel],
|
2217 |
+
$this->packet_size_client_to_server[$client_channel],
|
2218 |
+
$this->_string_shift($data, $this->packet_size_client_to_server[$client_channel])
|
2219 |
+
);
|
2220 |
+
|
2221 |
+
if (!$this->_send_binary_packet($packet)) {
|
2222 |
+
return false;
|
2223 |
+
}
|
2224 |
+
}
|
2225 |
+
|
2226 |
+
// resize the window, if appropriate
|
2227 |
+
$this->window_size_client_to_server[$client_channel]-= strlen($data);
|
2228 |
+
if ($this->window_size_client_to_server[$client_channel] < 0) {
|
2229 |
+
$packet = pack('CNN', NET_SSH2_MSG_CHANNEL_WINDOW_ADJUST, $this->server_channels[$client_channel], $this->window_size);
|
2230 |
+
if (!$this->_send_binary_packet($packet)) {
|
2231 |
+
return false;
|
2232 |
+
}
|
2233 |
+
$this->window_size_client_to_server[$client_channel]+= $this->window_size;
|
2234 |
+
}
|
2235 |
+
|
2236 |
+
return $this->_send_binary_packet(pack('CN2a*',
|
2237 |
+
NET_SSH2_MSG_CHANNEL_DATA,
|
2238 |
+
$this->server_channels[$client_channel],
|
2239 |
+
strlen($data),
|
2240 |
+
$data));
|
2241 |
+
}
|
2242 |
+
|
2243 |
+
/**
|
2244 |
+
* Closes and flushes a channel
|
2245 |
+
*
|
2246 |
+
* Net_SSH2 doesn't properly close most channels. For exec() channels are normally closed by the server
|
2247 |
+
* and for SFTP channels are presumably closed when the client disconnects. This functions is intended
|
2248 |
+
* for SCP more than anything.
|
2249 |
+
*
|
2250 |
+
* @param Integer $client_channel
|
2251 |
+
* @return Boolean
|
2252 |
+
* @access private
|
2253 |
+
*/
|
2254 |
+
function _close_channel($client_channel)
|
2255 |
+
{
|
2256 |
+
// see http://tools.ietf.org/html/rfc4254#section-5.3
|
2257 |
+
|
2258 |
+
$packet = pack('CN',
|
2259 |
+
NET_SSH2_MSG_CHANNEL_EOF,
|
2260 |
+
$this->server_channels[$client_channel]);
|
2261 |
+
if (!$this->_send_binary_packet($packet)) {
|
2262 |
+
return false;
|
2263 |
+
}
|
2264 |
+
|
2265 |
+
while ($this->_get_channel_packet($client_channel) !== true);
|
2266 |
+
}
|
2267 |
+
|
2268 |
+
/**
|
2269 |
+
* Disconnect
|
2270 |
+
*
|
2271 |
+
* @param Integer $reason
|
2272 |
+
* @return Boolean
|
2273 |
+
* @access private
|
2274 |
+
*/
|
2275 |
+
function _disconnect($reason)
|
2276 |
+
{
|
2277 |
+
if ($this->bitmap) {
|
2278 |
+
$data = pack('CNNa*Na*', NET_SSH2_MSG_DISCONNECT, $reason, 0, '', 0, '');
|
2279 |
+
$this->_send_binary_packet($data);
|
2280 |
+
$this->bitmap = 0;
|
2281 |
+
fclose($this->fsock);
|
2282 |
+
return false;
|
2283 |
+
}
|
2284 |
+
}
|
2285 |
+
|
2286 |
+
/**
|
2287 |
+
* String Shift
|
2288 |
+
*
|
2289 |
+
* Inspired by array_shift
|
2290 |
+
*
|
2291 |
+
* @param String $string
|
2292 |
+
* @param optional Integer $index
|
2293 |
+
* @return String
|
2294 |
+
* @access private
|
2295 |
+
*/
|
2296 |
+
function _string_shift(&$string, $index = 1)
|
2297 |
+
{
|
2298 |
+
$substr = substr($string, 0, $index);
|
2299 |
+
$string = substr($string, $index);
|
2300 |
+
return $substr;
|
2301 |
+
}
|
2302 |
+
|
2303 |
+
/**
|
2304 |
+
* Define Array
|
2305 |
+
*
|
2306 |
+
* Takes any number of arrays whose indices are integers and whose values are strings and defines a bunch of
|
2307 |
+
* named constants from it, using the value as the name of the constant and the index as the value of the constant.
|
2308 |
+
* If any of the constants that would be defined already exists, none of the constants will be defined.
|
2309 |
+
*
|
2310 |
+
* @param Array $array
|
2311 |
+
* @access private
|
2312 |
+
*/
|
2313 |
+
function _define_array()
|
2314 |
+
{
|
2315 |
+
$args = func_get_args();
|
2316 |
+
foreach ($args as $arg) {
|
2317 |
+
foreach ($arg as $key=>$value) {
|
2318 |
+
if (!defined($value)) {
|
2319 |
+
define($value, $key);
|
2320 |
+
} else {
|
2321 |
+
break 2;
|
2322 |
+
}
|
2323 |
+
}
|
2324 |
+
}
|
2325 |
+
}
|
2326 |
+
|
2327 |
+
/**
|
2328 |
+
* Returns a log of the packets that have been sent and received.
|
2329 |
+
*
|
2330 |
+
* Returns a string if NET_SSH2_LOGGING == NET_SSH2_LOG_COMPLEX, an array if NET_SSH2_LOGGING == NET_SSH2_LOG_SIMPLE and false if !defined('NET_SSH2_LOGGING')
|
2331 |
+
*
|
2332 |
+
* @access public
|
2333 |
+
* @return String or Array
|
2334 |
+
*/
|
2335 |
+
function getLog()
|
2336 |
+
{
|
2337 |
+
if (!defined('NET_SSH2_LOGGING')) {
|
2338 |
+
return false;
|
2339 |
+
}
|
2340 |
+
|
2341 |
+
switch (NET_SSH2_LOGGING) {
|
2342 |
+
case NET_SSH2_LOG_SIMPLE:
|
2343 |
+
return $this->message_number_log;
|
2344 |
+
break;
|
2345 |
+
case NET_SSH2_LOG_COMPLEX:
|
2346 |
+
return $this->_format_log($this->message_log, $this->message_number_log);
|
2347 |
+
break;
|
2348 |
+
default:
|
2349 |
+
return false;
|
2350 |
+
}
|
2351 |
+
}
|
2352 |
+
|
2353 |
+
/**
|
2354 |
+
* Formats a log for printing
|
2355 |
+
*
|
2356 |
+
* @param Array $message_log
|
2357 |
+
* @param Array $message_number_log
|
2358 |
+
* @access private
|
2359 |
+
* @return String
|
2360 |
+
*/
|
2361 |
+
function _format_log($message_log, $message_number_log)
|
2362 |
+
{
|
2363 |
+
static $boundary = ':', $long_width = 65, $short_width = 16;
|
2364 |
+
|
2365 |
+
$output = '';
|
2366 |
+
for ($i = 0; $i < count($message_log); $i++) {
|
2367 |
+
$output.= $message_number_log[$i] . "\r\n";
|
2368 |
+
$current_log = $message_log[$i];
|
2369 |
+
$j = 0;
|
2370 |
+
do {
|
2371 |
+
if (!empty($current_log)) {
|
2372 |
+
$output.= str_pad(dechex($j), 7, '0', STR_PAD_LEFT) . '0 ';
|
2373 |
+
}
|
2374 |
+
$fragment = $this->_string_shift($current_log, $short_width);
|
2375 |
+
$hex = substr(
|
2376 |
+
preg_replace(
|
2377 |
+
'#(.)#es',
|
2378 |
+
'"' . $boundary . '" . str_pad(dechex(ord(substr("\\1", -1))), 2, "0", STR_PAD_LEFT)',
|
2379 |
+
$fragment),
|
2380 |
+
strlen($boundary)
|
2381 |
+
);
|
2382 |
+
// replace non ASCII printable characters with dots
|
2383 |
+
// http://en.wikipedia.org/wiki/ASCII#ASCII_printable_characters
|
2384 |
+
// also replace < with a . since < messes up the output on web browsers
|
2385 |
+
$raw = preg_replace('#[^\x20-\x7E]|<#', '.', $fragment);
|
2386 |
+
$output.= str_pad($hex, $long_width - $short_width, ' ') . $raw . "\r\n";
|
2387 |
+
$j++;
|
2388 |
+
} while (!empty($current_log));
|
2389 |
+
$output.= "\r\n";
|
2390 |
+
}
|
2391 |
+
|
2392 |
+
return $output;
|
2393 |
+
}
|
2394 |
+
|
2395 |
+
/**
|
2396 |
+
* Returns all errors
|
2397 |
+
*
|
2398 |
+
* @return String
|
2399 |
+
* @access public
|
2400 |
+
*/
|
2401 |
+
function getErrors()
|
2402 |
+
{
|
2403 |
+
return $this->errors;
|
2404 |
+
}
|
2405 |
+
|
2406 |
+
/**
|
2407 |
+
* Returns the last error
|
2408 |
+
*
|
2409 |
+
* @return String
|
2410 |
+
* @access public
|
2411 |
+
*/
|
2412 |
+
function getLastError()
|
2413 |
+
{
|
2414 |
+
return $this->errors[count($this->errors) - 1];
|
2415 |
+
}
|
2416 |
+
|
2417 |
+
/**
|
2418 |
+
* Return the server identification.
|
2419 |
+
*
|
2420 |
+
* @return String
|
2421 |
+
* @access public
|
2422 |
+
*/
|
2423 |
+
function getServerIdentification()
|
2424 |
+
{
|
2425 |
+
return $this->server_identifier;
|
2426 |
+
}
|
2427 |
+
|
2428 |
+
/**
|
2429 |
+
* Return a list of the key exchange algorithms the server supports.
|
2430 |
+
*
|
2431 |
+
* @return Array
|
2432 |
+
* @access public
|
2433 |
+
*/
|
2434 |
+
function getKexAlgorithms()
|
2435 |
+
{
|
2436 |
+
return $this->kex_algorithms;
|
2437 |
+
}
|
2438 |
+
|
2439 |
+
/**
|
2440 |
+
* Return a list of the host key (public key) algorithms the server supports.
|
2441 |
+
*
|
2442 |
+
* @return Array
|
2443 |
+
* @access public
|
2444 |
+
*/
|
2445 |
+
function getServerHostKeyAlgorithms()
|
2446 |
+
{
|
2447 |
+
return $this->server_host_key_algorithms;
|
2448 |
+
}
|
2449 |
+
|
2450 |
+
/**
|
2451 |
+
* Return a list of the (symmetric key) encryption algorithms the server supports, when receiving stuff from the client.
|
2452 |
+
*
|
2453 |
+
* @return Array
|
2454 |
+
* @access public
|
2455 |
+
*/
|
2456 |
+
function getEncryptionAlgorithmsClient2Server()
|
2457 |
+
{
|
2458 |
+
return $this->encryption_algorithms_client_to_server;
|
2459 |
+
}
|
2460 |
+
|
2461 |
+
/**
|
2462 |
+
* Return a list of the (symmetric key) encryption algorithms the server supports, when sending stuff to the client.
|
2463 |
+
*
|
2464 |
+
* @return Array
|
2465 |
+
* @access public
|
2466 |
+
*/
|
2467 |
+
function getEncryptionAlgorithmsServer2Client()
|
2468 |
+
{
|
2469 |
+
return $this->encryption_algorithms_server_to_client;
|
2470 |
+
}
|
2471 |
+
|
2472 |
+
/**
|
2473 |
+
* Return a list of the MAC algorithms the server supports, when receiving stuff from the client.
|
2474 |
+
*
|
2475 |
+
* @return Array
|
2476 |
+
* @access public
|
2477 |
+
*/
|
2478 |
+
function getMACAlgorithmsClient2Server()
|
2479 |
+
{
|
2480 |
+
return $this->mac_algorithms_client_to_server;
|
2481 |
+
}
|
2482 |
+
|
2483 |
+
/**
|
2484 |
+
* Return a list of the MAC algorithms the server supports, when sending stuff to the client.
|
2485 |
+
*
|
2486 |
+
* @return Array
|
2487 |
+
* @access public
|
2488 |
+
*/
|
2489 |
+
function getMACAlgorithmsServer2Client()
|
2490 |
+
{
|
2491 |
+
return $this->mac_algorithms_server_to_client;
|
2492 |
+
}
|
2493 |
+
|
2494 |
+
/**
|
2495 |
+
* Return a list of the compression algorithms the server supports, when receiving stuff from the client.
|
2496 |
+
*
|
2497 |
+
* @return Array
|
2498 |
+
* @access public
|
2499 |
+
*/
|
2500 |
+
function getCompressionAlgorithmsClient2Server()
|
2501 |
+
{
|
2502 |
+
return $this->compression_algorithms_client_to_server;
|
2503 |
+
}
|
2504 |
+
|
2505 |
+
/**
|
2506 |
+
* Return a list of the compression algorithms the server supports, when sending stuff to the client.
|
2507 |
+
*
|
2508 |
+
* @return Array
|
2509 |
+
* @access public
|
2510 |
+
*/
|
2511 |
+
function getCompressionAlgorithmsServer2Client()
|
2512 |
+
{
|
2513 |
+
return $this->compression_algorithms_server_to_client;
|
2514 |
+
}
|
2515 |
+
|
2516 |
+
/**
|
2517 |
+
* Return a list of the languages the server supports, when sending stuff to the client.
|
2518 |
+
*
|
2519 |
+
* @return Array
|
2520 |
+
* @access public
|
2521 |
+
*/
|
2522 |
+
function getLanguagesServer2Client()
|
2523 |
+
{
|
2524 |
+
return $this->languages_server_to_client;
|
2525 |
+
}
|
2526 |
+
|
2527 |
+
/**
|
2528 |
+
* Return a list of the languages the server supports, when receiving stuff from the client.
|
2529 |
+
*
|
2530 |
+
* @return Array
|
2531 |
+
* @access public
|
2532 |
+
*/
|
2533 |
+
function getLanguagesClient2Server()
|
2534 |
+
{
|
2535 |
+
return $this->languages_client_to_server;
|
2536 |
+
}
|
2537 |
+
|
2538 |
+
/**
|
2539 |
+
* Returns the server public host key.
|
2540 |
+
*
|
2541 |
+
* Caching this the first time you connect to a server and checking the result on subsequent connections
|
2542 |
+
* is recommended. Returns false if the server signature is not signed correctly with the public host key.
|
2543 |
+
*
|
2544 |
+
* @return Mixed
|
2545 |
+
* @access public
|
2546 |
+
*/
|
2547 |
+
function getServerPublicHostKey()
|
2548 |
+
{
|
2549 |
+
$signature = $this->signature;
|
2550 |
+
$server_public_host_key = $this->server_public_host_key;
|
2551 |
+
|
2552 |
+
extract(unpack('Nlength', $this->_string_shift($server_public_host_key, 4)));
|
2553 |
+
$this->_string_shift($server_public_host_key, $length);
|
2554 |
+
|
2555 |
+
switch ($this->signature_format) {
|
2556 |
+
case 'ssh-dss':
|
2557 |
+
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
2558 |
+
$p = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
|
2559 |
+
|
2560 |
+
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
2561 |
+
$q = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
|
2562 |
+
|
2563 |
+
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
2564 |
+
$g = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
|
2565 |
+
|
2566 |
+
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
2567 |
+
$y = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
|
2568 |
+
|
2569 |
+
/* The value for 'dss_signature_blob' is encoded as a string containing
|
2570 |
+
r, followed by s (which are 160-bit integers, without lengths or
|
2571 |
+
padding, unsigned, and in network byte order). */
|
2572 |
+
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
|
2573 |
+
if ($temp['length'] != 40) {
|
2574 |
+
user_error('Invalid signature', E_USER_NOTICE);
|
2575 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
2576 |
+
}
|
2577 |
+
|
2578 |
+
$r = new Math_BigInteger($this->_string_shift($signature, 20), 256);
|
2579 |
+
$s = new Math_BigInteger($this->_string_shift($signature, 20), 256);
|
2580 |
+
|
2581 |
+
if ($r->compare($q) >= 0 || $s->compare($q) >= 0) {
|
2582 |
+
user_error('Invalid signature', E_USER_NOTICE);
|
2583 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
2584 |
+
}
|
2585 |
+
|
2586 |
+
$w = $s->modInverse($q);
|
2587 |
+
|
2588 |
+
$u1 = $w->multiply(new Math_BigInteger(sha1($this->exchange_hash), 16));
|
2589 |
+
list(, $u1) = $u1->divide($q);
|
2590 |
+
|
2591 |
+
$u2 = $w->multiply($r);
|
2592 |
+
list(, $u2) = $u2->divide($q);
|
2593 |
+
|
2594 |
+
$g = $g->modPow($u1, $p);
|
2595 |
+
$y = $y->modPow($u2, $p);
|
2596 |
+
|
2597 |
+
$v = $g->multiply($y);
|
2598 |
+
list(, $v) = $v->divide($p);
|
2599 |
+
list(, $v) = $v->divide($q);
|
2600 |
+
|
2601 |
+
if (!$v->equals($r)) {
|
2602 |
+
user_error('Bad server signature', E_USER_NOTICE);
|
2603 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
2604 |
+
}
|
2605 |
+
|
2606 |
+
break;
|
2607 |
+
case 'ssh-rsa':
|
2608 |
+
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
2609 |
+
$e = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
|
2610 |
+
|
2611 |
+
$temp = unpack('Nlength', $this->_string_shift($server_public_host_key, 4));
|
2612 |
+
$n = new Math_BigInteger($this->_string_shift($server_public_host_key, $temp['length']), -256);
|
2613 |
+
$nLength = $temp['length'];
|
2614 |
+
|
2615 |
+
/*
|
2616 |
+
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
|
2617 |
+
$signature = $this->_string_shift($signature, $temp['length']);
|
2618 |
+
|
2619 |
+
if (!class_exists('Crypt_RSA')) {
|
2620 |
+
require_once('Crypt/RSA.php');
|
2621 |
+
}
|
2622 |
+
|
2623 |
+
$rsa = new Crypt_RSA();
|
2624 |
+
$rsa->setSignatureMode(CRYPT_RSA_SIGNATURE_PKCS1);
|
2625 |
+
$rsa->loadKey(array('e' => $e, 'n' => $n), CRYPT_RSA_PUBLIC_FORMAT_RAW);
|
2626 |
+
if (!$rsa->verify($this->exchange_hash, $signature)) {
|
2627 |
+
user_error('Bad server signature', E_USER_NOTICE);
|
2628 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
2629 |
+
}
|
2630 |
+
*/
|
2631 |
+
|
2632 |
+
$temp = unpack('Nlength', $this->_string_shift($signature, 4));
|
2633 |
+
$s = new Math_BigInteger($this->_string_shift($signature, $temp['length']), 256);
|
2634 |
+
|
2635 |
+
// validate an RSA signature per "8.2 RSASSA-PKCS1-v1_5", "5.2.2 RSAVP1", and "9.1 EMSA-PSS" in the
|
2636 |
+
// following URL:
|
2637 |
+
// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1.pdf
|
2638 |
+
|
2639 |
+
// also, see SSHRSA.c (rsa2_verifysig) in PuTTy's source.
|
2640 |
+
|
2641 |
+
if ($s->compare(new Math_BigInteger()) < 0 || $s->compare($n->subtract(new Math_BigInteger(1))) > 0) {
|
2642 |
+
user_error('Invalid signature', E_USER_NOTICE);
|
2643 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_KEY_EXCHANGE_FAILED);
|
2644 |
+
}
|
2645 |
+
|
2646 |
+
$s = $s->modPow($e, $n);
|
2647 |
+
$s = $s->toBytes();
|
2648 |
+
|
2649 |
+
$h = pack('N4H*', 0x00302130, 0x0906052B, 0x0E03021A, 0x05000414, sha1($this->exchange_hash));
|
2650 |
+
$h = chr(0x01) . str_repeat(chr(0xFF), $nLength - 3 - strlen($h)) . $h;
|
2651 |
+
|
2652 |
+
if ($s != $h) {
|
2653 |
+
user_error('Bad server signature', E_USER_NOTICE);
|
2654 |
+
return $this->_disconnect(NET_SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE);
|
2655 |
+
}
|
2656 |
+
}
|
2657 |
+
|
2658 |
+
return $this->server_public_host_key;
|
2659 |
+
}
|
2660 |
+
}
|
classes/phpseclib/PHP/Compat/Function/array_fill.php
ADDED
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// $Id: array_fill.php,v 1.1 2007/07/02 04:19:55 terrafrost Exp $
|
3 |
+
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Replace array_fill()
|
7 |
+
*
|
8 |
+
* @category PHP
|
9 |
+
* @package PHP_Compat
|
10 |
+
* @license http://www.opensource.org/licenses/mit-license.html MIT License
|
11 |
+
* @copyright 2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
|
12 |
+
* @link http://php.net/function.array_fill
|
13 |
+
* @author Jim Wigginton <terrafrost@php.net>
|
14 |
+
* @version $Revision: 1.1 $
|
15 |
+
* @since PHP 4.2.0
|
16 |
+
*/
|
17 |
+
function php_compat_array_fill($start_index, $num, $value)
|
18 |
+
{
|
19 |
+
if ($num <= 0) {
|
20 |
+
user_error('array_fill(): Number of elements must be positive', E_USER_WARNING);
|
21 |
+
|
22 |
+
return false;
|
23 |
+
}
|
24 |
+
|
25 |
+
$temp = array();
|
26 |
+
|
27 |
+
$end_index = $start_index + $num;
|
28 |
+
for ($i = (int) $start_index; $i < $end_index; $i++) {
|
29 |
+
$temp[$i] = $value;
|
30 |
+
}
|
31 |
+
|
32 |
+
return $temp;
|
33 |
+
}
|
34 |
+
|
35 |
+
// Define
|
36 |
+
if (!function_exists('array_fill')) {
|
37 |
+
function array_fill($start_index, $num, $value)
|
38 |
+
{
|
39 |
+
return php_compat_array_fill($start_index, $num, $value);
|
40 |
+
}
|
41 |
+
}
|
classes/phpseclib/PHP/Compat/Function/bcpowmod.php
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// $Id: bcpowmod.php,v 1.1 2007-07-02 04:19:55 terrafrost Exp $
|
3 |
+
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Replace bcpowmod()
|
7 |
+
*
|
8 |
+
* @category PHP
|
9 |
+
* @package PHP_Compat
|
10 |
+
* @license LGPL - http://www.gnu.org/licenses/lgpl.html
|
11 |
+
* @copyright 2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
|
12 |
+
* @link http://php.net/function.bcpowmod
|
13 |
+
* @author Sara Golemon <pollita@php.net>
|
14 |
+
* @version $Revision: 1.1 $
|
15 |
+
* @since PHP 5.0.0
|
16 |
+
* @require PHP 4.0.0 (user_error)
|
17 |
+
*/
|
18 |
+
function php_compat_bcpowmod($x, $y, $modulus, $scale = 0)
|
19 |
+
{
|
20 |
+
// Sanity check
|
21 |
+
if (!is_scalar($x)) {
|
22 |
+
user_error('bcpowmod() expects parameter 1 to be string, ' .
|
23 |
+
gettype($x) . ' given', E_USER_WARNING);
|
24 |
+
return false;
|
25 |
+
}
|
26 |
+
|
27 |
+
if (!is_scalar($y)) {
|
28 |
+
user_error('bcpowmod() expects parameter 2 to be string, ' .
|
29 |
+
gettype($y) . ' given', E_USER_WARNING);
|
30 |
+
return false;
|
31 |
+
}
|
32 |
+
|
33 |
+
if (!is_scalar($modulus)) {
|
34 |
+
user_error('bcpowmod() expects parameter 3 to be string, ' .
|
35 |
+
gettype($modulus) . ' given', E_USER_WARNING);
|
36 |
+
return false;
|
37 |
+
}
|
38 |
+
|
39 |
+
if (!is_scalar($scale)) {
|
40 |
+
user_error('bcpowmod() expects parameter 4 to be integer, ' .
|
41 |
+
gettype($scale) . ' given', E_USER_WARNING);
|
42 |
+
return false;
|
43 |
+
}
|
44 |
+
|
45 |
+
$t = '1';
|
46 |
+
while (bccomp($y, '0')) {
|
47 |
+
if (bccomp(bcmod($y, '2'), '0')) {
|
48 |
+
$t = bcmod(bcmul($t, $x), $modulus);
|
49 |
+
$y = bcsub($y, '1');
|
50 |
+
}
|
51 |
+
|
52 |
+
$x = bcmod(bcmul($x, $x), $modulus);
|
53 |
+
$y = bcdiv($y, '2');
|
54 |
+
}
|
55 |
+
|
56 |
+
return $t;
|
57 |
+
}
|
58 |
+
|
59 |
+
|
60 |
+
// Define
|
61 |
+
if (!function_exists('bcpowmod')) {
|
62 |
+
function bcpowmod($x, $y, $modulus, $scale = 0)
|
63 |
+
{
|
64 |
+
return php_compat_bcpowmod($x, $y, $modulus, $scale);
|
65 |
+
}
|
66 |
+
}
|
classes/phpseclib/PHP/Compat/Function/str_split.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* Replace str_split()
|
4 |
+
*
|
5 |
+
* @category PHP
|
6 |
+
* @package PHP_Compat
|
7 |
+
* @license LGPL - http://www.gnu.org/licenses/lgpl.html
|
8 |
+
* @copyright 2004-2007 Aidan Lister <aidan@php.net>, Arpad Ray <arpad@php.net>
|
9 |
+
* @link http://php.net/function.str_split
|
10 |
+
* @author Aidan Lister <aidan@php.net>
|
11 |
+
* @version $Revision: 1.1 $
|
12 |
+
* @since PHP 5
|
13 |
+
* @require PHP 4.0.0 (user_error)
|
14 |
+
*/
|
15 |
+
function php_compat_str_split($string, $split_length = 1)
|
16 |
+
{
|
17 |
+
if (!is_scalar($split_length)) {
|
18 |
+
user_error('str_split() expects parameter 2 to be long, ' .
|
19 |
+
gettype($split_length) . ' given', E_USER_WARNING);
|
20 |
+
return false;
|
21 |
+
}
|
22 |
+
|
23 |
+
$split_length = (int) $split_length;
|
24 |
+
if ($split_length < 1) {
|
25 |
+
user_error('str_split() The length of each segment must be greater than zero', E_USER_WARNING);
|
26 |
+
return false;
|
27 |
+
}
|
28 |
+
|
29 |
+
// Select split method
|
30 |
+
if ($split_length < 65536) {
|
31 |
+
// Faster, but only works for less than 2^16
|
32 |
+
preg_match_all('/.{1,' . $split_length . '}/s', $string, $matches);
|
33 |
+
return $matches[0];
|
34 |
+
} else {
|
35 |
+
// Required due to preg limitations
|
36 |
+
$arr = array();
|
37 |
+
$idx = 0;
|
38 |
+
$pos = 0;
|
39 |
+
$len = strlen($string);
|
40 |
+
|
41 |
+
while ($len > 0) {
|
42 |
+
$blk = ($len < $split_length) ? $len : $split_length;
|
43 |
+
$arr[$idx++] = substr($string, $pos, $blk);
|
44 |
+
$pos += $blk;
|
45 |
+
$len -= $blk;
|
46 |
+
}
|
47 |
+
|
48 |
+
return $arr;
|
49 |
+
}
|
50 |
+
}
|
51 |
+
|
52 |
+
|
53 |
+
// Define
|
54 |
+
if (!function_exists('str_split')) {
|
55 |
+
function str_split($string, $split_length = 1)
|
56 |
+
{
|
57 |
+
return php_compat_str_split($string, $split_length);
|
58 |
+
}
|
59 |
+
}
|
cloner.config.php
CHANGED
@@ -1,4 +1,7 @@
|
|
1 |
<?php
|
|
|
|
|
|
|
2 |
$_CONFIG['license_code']="";
|
3 |
$_CONFIG['backup_path']="./";
|
4 |
$_CONFIG['clonerPath']="./";
|
@@ -42,12 +45,22 @@ $_CONFIG['system_mdatabases']="0";
|
|
42 |
$_CONFIG['recordsPerSession']= "10000";
|
43 |
$_CONFIG['excludeFilesSize'] = "-1";
|
44 |
$_CONFIG['splitBackupSize'] = "2048"; //MB
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
45 |
|
46 |
### Defaults
|
47 |
$script_dir = str_replace("\\","/",dirname(__FILE__));
|
48 |
|
49 |
-
$_CONFIG['jcuser'] = 'admin';
|
50 |
-
$_CONFIG['jcpass'] = md5('admin');
|
51 |
$_CONFIG['mem']="0";
|
52 |
$_CONFIG['archive_type']="0";
|
53 |
$_CONFIG['backup_refresh'] = "1";
|
@@ -57,8 +70,6 @@ $_CONFIG['enable_db_backup'] = '0';
|
|
57 |
|
58 |
###Wordpress specific configuration
|
59 |
|
60 |
-
/*if(@include("../../../wp-config.php")){
|
61 |
-
|
62 |
$_CONFIG["enable_db_backup"] = 1;
|
63 |
$_CONFIG['mysql_host'] = DB_HOST;
|
64 |
$_CONFIG['mysql_user'] = DB_USER;
|
@@ -66,23 +77,6 @@ $_CONFIG['enable_db_backup'] = '0';
|
|
66 |
$_CONFIG['mysql_database'] = DB_NAME;
|
67 |
|
68 |
|
69 |
-
}*/
|
70 |
-
|
71 |
-
if(@file_exists("../../../wp-config.php")){
|
72 |
-
|
73 |
-
$content = file_get_contents("../../../wp-config.php");
|
74 |
-
$content = str_replace("require_once","#require_once", $content);
|
75 |
-
$content = str_replace(array("<?php","<?","?>"),array("","",""), $content);
|
76 |
-
eval($content);
|
77 |
-
|
78 |
-
$_CONFIG["enable_db_backup"] = 1;
|
79 |
-
$_CONFIG['mysql_host'] = DB_HOST;
|
80 |
-
$_CONFIG['mysql_user'] = DB_USER;
|
81 |
-
$_CONFIG['mysql_pass'] = DB_PASSWORD;
|
82 |
-
$_CONFIG['mysql_database'] = DB_NAME;
|
83 |
-
|
84 |
-
|
85 |
-
}
|
86 |
|
87 |
$script_dir = str_replace("wp-content/plugins/xcloner-backup-and-restore","", $script_dir);
|
88 |
|
@@ -93,5 +87,10 @@ $_CONFIG['clonerPath'] = str_replace("\\","/", $_CONFIG['clonerPath']);
|
|
93 |
|
94 |
$_CONFIG['mosConfig_live_site']=$_SERVER['HTTP_HOST'];
|
95 |
|
|
|
|
|
|
|
|
|
|
|
96 |
|
97 |
?>
|
1 |
<?php
|
2 |
+
|
3 |
+
defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
|
4 |
+
|
5 |
$_CONFIG['license_code']="";
|
6 |
$_CONFIG['backup_path']="./";
|
7 |
$_CONFIG['clonerPath']="./";
|
45 |
$_CONFIG['recordsPerSession']= "10000";
|
46 |
$_CONFIG['excludeFilesSize'] = "-1";
|
47 |
$_CONFIG['splitBackupSize'] = "2048"; //MB
|
48 |
+
$_CONFIG['select_lang'] = "english";
|
49 |
+
|
50 |
+
$_CONFIG["cron_amazon_active"]="";
|
51 |
+
$_CONFIG["cron_amazon_awsAccessKey"]="";
|
52 |
+
$_CONFIG["cron_amazon_awsSecretKey"]="";
|
53 |
+
$_CONFIG["cron_amazon_bucket"]="";
|
54 |
+
$_CONFIG["cron_amazon_dirname"]="";
|
55 |
+
$_CONFIG["cron_amazon_ssl"]="";
|
56 |
+
$_CONFIG["cron_dropbox_active"]="";
|
57 |
+
$_CONFIG["cron_dropbox_Key"]="";
|
58 |
+
$_CONFIG["cron_dropbox_Secret"]="";
|
59 |
+
$_CONFIG["cron_dropbox_dirname"]="";
|
60 |
|
61 |
### Defaults
|
62 |
$script_dir = str_replace("\\","/",dirname(__FILE__));
|
63 |
|
|
|
|
|
64 |
$_CONFIG['mem']="0";
|
65 |
$_CONFIG['archive_type']="0";
|
66 |
$_CONFIG['backup_refresh'] = "1";
|
70 |
|
71 |
###Wordpress specific configuration
|
72 |
|
|
|
|
|
73 |
$_CONFIG["enable_db_backup"] = 1;
|
74 |
$_CONFIG['mysql_host'] = DB_HOST;
|
75 |
$_CONFIG['mysql_user'] = DB_USER;
|
77 |
$_CONFIG['mysql_database'] = DB_NAME;
|
78 |
|
79 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
|
81 |
$script_dir = str_replace("wp-content/plugins/xcloner-backup-and-restore","", $script_dir);
|
82 |
|
87 |
|
88 |
$_CONFIG['mosConfig_live_site']=$_SERVER['HTTP_HOST'];
|
89 |
|
90 |
+
foreach($_CONFIG as $key=>$value){
|
91 |
+
$newVal = get_site_option("xcloner_".$key);
|
92 |
+
if($newVal !== FALSE)
|
93 |
+
$_CONFIG[$key] = $newVal;
|
94 |
+
}
|
95 |
|
96 |
?>
|
cloner.cron.php
CHANGED
@@ -7,68 +7,59 @@
|
|
7 |
* License: GNU/GPL
|
8 |
* Email: admin@xcloner.com
|
9 |
* Revision: 1.0
|
10 |
-
* Date: July
|
11 |
**/
|
12 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
13 |
// Set flag that this is a parent file
|
14 |
@error_reporting(E_ALL^E_NOTICE);
|
15 |
@set_time_limit('3600');
|
16 |
define( '_VALID_MOS', 1 );
|
|
|
17 |
|
18 |
include_once("admin.cloner.html.php");
|
19 |
include_once("cloner.functions.php");
|
20 |
|
21 |
-
|
22 |
-
|
23 |
-
####### VERIFY IP ACCESS
|
24 |
-
$ip_list = @explode("\r\n", $_CONFIG['cron_ip']);
|
25 |
-
$ip_list[] = $_SERVER['SERVER_ADDR'];
|
26 |
-
$curent_ip = $_SERVER["REMOTE_ADDR"];
|
27 |
-
|
28 |
-
if(!in_array($curent_ip, $ip_list)){
|
29 |
-
|
30 |
-
echo "Access Denied for ip $curent_ip!";
|
31 |
-
exit;
|
32 |
-
|
33 |
-
}
|
34 |
-
#########################
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
|
39 |
$script_dir = str_replace("\\","/",dirname(__FILE__));
|
40 |
if(is_dir($script_dir)){
|
41 |
-
|
42 |
chdir($script_dir);
|
43 |
|
44 |
}
|
45 |
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
if($argv[1] != ""){
|
50 |
-
|
51 |
-
$_REQUEST['config'] = $argv[1];
|
52 |
-
|
53 |
-
}
|
54 |
-
|
55 |
-
|
56 |
-
}
|
57 |
|
58 |
//filter the config request path
|
59 |
$_REQUEST['config'] = str_replace(array("..","/","\\"), array("","",""), trim($_REQUEST['config']));
|
60 |
|
61 |
-
if($_REQUEST['config'] != ""){
|
62 |
-
|
63 |
require_once( './configs/'.$_REQUEST['config'] );
|
64 |
-
|
65 |
$smsg = "Using configs/".$_REQUEST['config']." as configuration file";
|
66 |
-
|
67 |
}
|
68 |
else{
|
69 |
|
70 |
-
|
71 |
-
|
|
|
|
|
|
|
|
|
|
|
72 |
$smsg = "Using default configuration file";
|
73 |
|
74 |
}
|
@@ -78,6 +69,7 @@ require_once("restore/TAR.php");
|
|
78 |
|
79 |
$mosConfig_live_site = $_CONFIG['mosConfig_live_site'];
|
80 |
|
|
|
81 |
logxx($smsg);
|
82 |
|
83 |
|
@@ -95,26 +87,13 @@ if($_CONFIG['select_lang']!="")
|
|
95 |
if (file_exists( "language/".$mosConfig_lang.".php" )) {
|
96 |
include_once( "language/".$mosConfig_lang.".php" );
|
97 |
@include_once( "language/english.php" );
|
98 |
-
}
|
99 |
else{
|
100 |
include_once( "language/english.php" );
|
101 |
}
|
102 |
|
103 |
|
104 |
|
105 |
-
####### VERIFY IP ACCESS
|
106 |
-
/*$ip_list = @explode("\r\n", $_CONFIG['cron_ip']);
|
107 |
-
$ip_list[] = $_SERVER['SERVER_ADDR'];
|
108 |
-
$curent_ip = $_SERVER["REMOTE_ADDR"];
|
109 |
-
|
110 |
-
if(!in_array($curent_ip, $ip_list)){
|
111 |
-
|
112 |
-
echo "Access Denied for ip $curent_ip!";
|
113 |
-
exit;
|
114 |
-
|
115 |
-
}*/
|
116 |
-
#########################
|
117 |
-
|
118 |
$access=1;
|
119 |
$_REQUEST[cron_dbonly] = 0;
|
120 |
$_REQUEST[cron_access] = 1;
|
@@ -125,14 +104,14 @@ $_REQUEST['databases_incl'] = @explode(",",$_CONFIG[databases_incl_list]);
|
|
125 |
|
126 |
if($_CONFIG[cron_bname]!="")
|
127 |
$_REQUEST['bname'] = $_CONFIG[cron_bname];
|
128 |
-
|
129 |
-
|
130 |
function logxx($string = ""){
|
131 |
-
|
132 |
-
global $mail_log;
|
133 |
|
134 |
$return = "<b>$string</b><br />\r\n";
|
135 |
-
|
136 |
$mail_log .= $return;
|
137 |
|
138 |
echo $return;
|
@@ -148,12 +127,7 @@ logxx("Starting XCloner for site $mosConfig_live_site at ".date("Y-m-d H:i"));
|
|
148 |
$f_arr = array(); $f = 0;
|
149 |
$s_arr = array(); $s = 0;
|
150 |
$d_arr[$d] = $_CONFIG['backup_path'];
|
151 |
-
|
152 |
-
#recurseFiles($d_arr, $ds_arr, $f_arr, $s_arr, $d, $f, $s, $excludefolders, '');
|
153 |
-
#$excludedFolders = confirmBackup('nohtml');
|
154 |
-
#logxx("Done");
|
155 |
-
|
156 |
-
|
157 |
|
158 |
if($_CONFIG['cron_btype']==0){
|
159 |
$_REQUEST[dbbackup] = 1;
|
@@ -175,7 +149,7 @@ if($_CONFIG['cron_btype']==2){
|
|
175 |
$GLOBALS['_CONFIG'] = $_CONFIG;
|
176 |
$_REQUEST[cron_dbonly] = 1;
|
177 |
#}
|
178 |
-
|
179 |
logxx("Creating an sql only backup");
|
180 |
$msg = "database backup";
|
181 |
}
|
@@ -190,89 +164,115 @@ $source_file = $clonerPath."/".$file;
|
|
190 |
logxx("Backup file: ".$source_file);
|
191 |
$bsize = getFileSizeText(filesize($source_file));
|
192 |
|
193 |
-
if($_CONFIG['cron_send']==1)
|
194 |
-
######################################STARTING FTP TRANSFER##################
|
195 |
-
|
196 |
-
logxx("Starting ftp transfer:");
|
197 |
-
|
198 |
-
$source_files[] = $source_file;
|
199 |
-
$destination_files[] = $_CONFIG[cron_ftp_path]."/".$file;
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
// set up basic connection details
|
204 |
-
list($fhost, $fport) = explode(":",$_CONFIG[cron_ftp_server]);
|
205 |
-
if($fport == "")
|
206 |
-
$fport = '21';
|
207 |
-
|
208 |
-
$ftp_timeout = '3600';
|
209 |
-
|
210 |
-
// set up basic connection
|
211 |
-
if(!$_CONFIG[secure_ftp]){
|
212 |
-
$conn_id = ftp_connect($fhost, (int)$fport, (int)$ftp_timeout);
|
213 |
-
$connect = "Normal";
|
214 |
-
}
|
215 |
-
else{
|
216 |
-
$conn_id = ftp_ssl_connect($fhost, (int)$fport, (int)$ftp_timeout);
|
217 |
-
$connect = "Secure";
|
218 |
-
}
|
219 |
-
|
220 |
-
//$conn_id = ftp_connect($_CONFIG[cron_ftp_server]) or die("Could not connect to the ftp server ".$_CONFIG[cron_ftp_server]);
|
221 |
-
|
222 |
-
// login with username and password
|
223 |
-
$login_result = ftp_login($conn_id, $_CONFIG[cron_ftp_user], $_CONFIG[cron_ftp_pass])
|
224 |
-
or die("Authentification failed when connecting to the ftp server for user ".$_CONFIG[cron_ftp_user]." with pass".$_CONFIG[cron_ftp_pass]);
|
225 |
-
|
226 |
-
// check connection
|
227 |
-
if ((!$conn_id) || (!$login_result)) {
|
228 |
-
echo "<b style='color:red'>FTP connection has failed!</b>";
|
229 |
-
echo "<b style='color:red'>Attempted to connect to ".$_CONFIG[cron_ftp_server]." for user ".$_CONFIG[cron_ftp_user]."</b>";
|
230 |
-
return;
|
231 |
-
} else {
|
232 |
-
#echo "Connected to $_REQUEST[ftp_server], for user $_REQUEST[ftp_user]";
|
233 |
-
}
|
234 |
-
|
235 |
-
if($_CONFIG['system_ftptransfer']==1)
|
236 |
{
|
237 |
-
|
238 |
-
|
239 |
-
$
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
246 |
}
|
247 |
-
|
248 |
-
for($i=0;$i<sizeof($source_files);$i++)
|
249 |
{
|
250 |
-
// upload the file
|
251 |
-
$upload = ftp_put($conn_id, $destination_files[$i], $source_files[$i], FTP_BINARY);
|
252 |
-
|
253 |
-
// check upload status
|
254 |
-
if (!$upload) {
|
255 |
-
echo "<b style='color:red'>FTP upload has failed for file $source_files[$i] ! Stopping ....<br /></b>";return;
|
256 |
-
} else {
|
257 |
-
echo "<b>Upload success from file <i>$source_files[$i]</i> <br />to <i>$destination_files[$i]</i> ...<br /></b>";
|
258 |
-
}
|
259 |
-
|
260 |
-
}
|
261 |
-
|
262 |
-
// close the FTP stream
|
263 |
-
ftp_close($conn_id);
|
264 |
-
|
265 |
-
logxx("Ftp transfer finished succesfully!");
|
266 |
-
|
267 |
-
if($_CONFIG[cron_ftp_delb]==1){
|
268 |
-
|
269 |
-
@unlink($source_file);
|
270 |
-
logxx("Backup succesfully deleted from the original server!");
|
271 |
-
}
|
272 |
-
|
273 |
-
##############################################################################
|
274 |
-
}
|
275 |
-
elseif($_CONFIG['cron_send']==2){
|
276 |
#######################################STARTING Email TRANSFER################
|
277 |
logxx("Sending mail with backup");
|
278 |
|
@@ -283,19 +283,19 @@ elseif($_CONFIG['cron_send']==2){
|
|
283 |
Attached is the backup generated on $date
|
284 |
Source Filename: $source_file
|
285 |
Server: $mosConfig_live_site
|
286 |
-
|
287 |
Powered by http://www.xcloner.com - XCloner - Backup and Restore made easy!
|
288 |
</pre>
|
289 |
|
290 |
";
|
291 |
-
|
292 |
$ok = send_mail($mosConfig_mailfrom, "XCloner $msg", $message, $_CONFIG['cron_email_address'], $source_file);
|
293 |
-
|
294 |
#echo mosMail( $mosConfig_mailfrom, $mosConfig_fromname, $_CONFIG['cron_email_address'], "XCloner $msg", $message, $mode, '', '' );
|
295 |
if($ok)
|
296 |
logxx("Mail sent to ".$_CONFIG['cron_email_address']);
|
297 |
else
|
298 |
-
logxx("There was an error in sending the mail cron to ".$_CONFIG['cron_email_address']);
|
299 |
|
300 |
##############################################################################
|
301 |
}
|
@@ -309,9 +309,14 @@ include_once("classes/S3.php");
|
|
309 |
|
310 |
logxx();
|
311 |
|
312 |
-
|
|
|
|
|
|
|
313 |
|
314 |
-
|
|
|
|
|
315 |
|
316 |
$buckets = $s3->listBuckets();
|
317 |
|
@@ -335,6 +340,63 @@ if (($s3->putBucket($_CONFIG['cron_amazon_bucket'], "private")) || (@in_array($_
|
|
335 |
|
336 |
|
337 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
338 |
}
|
339 |
###### END
|
340 |
|
@@ -352,28 +414,34 @@ delete_older_backups($clonerPath);
|
|
352 |
###################END OLDER BACKUPS
|
353 |
|
354 |
$logemail = explode(";", $_CONFIG['cron_logemail']);
|
355 |
-
if(sizeof($logemail)>0){
|
356 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
357 |
for($i=0; $i<sizeof($logemail);$i++){
|
358 |
-
|
359 |
$email = trim($logemail[$i]);
|
360 |
if($email != ""){
|
361 |
-
|
362 |
$email_subject = "cron log ".time();
|
363 |
-
|
364 |
-
$headers ="From: \"
|
365 |
|
366 |
if(mail($email, $email_subject, strip_tags($mail_log), $headers)){
|
367 |
-
|
368 |
logxx ("Notification Mail was sent to $email");
|
369 |
-
|
370 |
}
|
371 |
-
|
372 |
-
|
373 |
}
|
374 |
-
|
375 |
}
|
376 |
-
|
377 |
}
|
378 |
|
379 |
logxx("<br />\n\nALL DONE! I will exit now from cron.");
|
@@ -395,78 +463,95 @@ getBackupFiles($d_arr, $f_arr, $s_arr, $d, $f);
|
|
395 |
if(is_array($f_arr))
|
396 |
foreach($f_arr as $file)
|
397 |
if(($file!='.')&&($file != '..')){
|
398 |
-
|
399 |
#logxx("Processing backup file $file");
|
400 |
$cfile = $_CONFIG['clonerPath']."/".$file;
|
401 |
-
|
402 |
$filemtime = filemtime($cfile) ;
|
403 |
-
|
404 |
$ftime= $filemtime + $_CONFIG['cron_file_delete']*24*60*60;
|
405 |
-
|
406 |
$ctime = time();
|
407 |
-
|
408 |
if($ftime < $ctime){
|
409 |
-
|
410 |
if(unlink($cfile))
|
411 |
logxx("Deleted backup file $file created on ".date("Y-m-d", $filemtime));
|
412 |
else
|
413 |
logxx("Could not delete backup file $file, please delete it manually");
|
414 |
-
|
415 |
}
|
416 |
-
|
417 |
}
|
418 |
|
419 |
}
|
420 |
|
421 |
function send_mail($email_from, $email_subject, $email_txt, $email_to, $fileatt){
|
422 |
-
$fileatt_type = "application/octet-stream"; // File Type
|
423 |
-
$fileatt_name = basename($fileatt); // Filename that will be used for the file as the attachment
|
424 |
$data = "";
|
425 |
|
426 |
-
$headers = "From: \"Cronbackup XCloner\" <".$email_from.">";
|
427 |
|
428 |
if($fileatt != ""){
|
429 |
-
|
430 |
if($file = @fopen($fileatt,'rb')){
|
431 |
-
|
432 |
$data = fread($file,filesize($fileatt));
|
433 |
-
|
434 |
fclose($file);
|
435 |
|
436 |
-
}
|
437 |
else{
|
438 |
logxx("Unable to open file $fileatt");
|
439 |
}
|
440 |
|
441 |
}
|
442 |
|
443 |
-
$semi_rand = md5(time());
|
444 |
-
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
|
445 |
-
|
446 |
-
$headers .= "\nMIME-Version: 1.0\n" .
|
447 |
-
"Content-Type: multipart/mixed;\n" .
|
448 |
-
" boundary=\"{$mime_boundary}\"";
|
449 |
|
450 |
-
$email_message .= "This is a multi-part message in MIME format.\n\n" .
|
451 |
-
"--{$mime_boundary}\n" .
|
452 |
-
"Content-Type:text/html; charset=\"iso-8859-1\"\n" .
|
453 |
-
"Content-Transfer-Encoding: 7bit\n\n" .
|
454 |
-
$email_txt . "\n\n";
|
455 |
|
456 |
-
$data = chunk_split(base64_encode($data));
|
457 |
|
458 |
-
$email_message .= "--{$mime_boundary}\n" .
|
459 |
-
"Content-Type: {$fileatt_type};\n" .
|
460 |
-
" name=\"{$fileatt_name}\"\n" .
|
461 |
-
//"Content-Disposition: attachment;\n" .
|
462 |
-
//" filename=\"{$fileatt_name}\"\n" .
|
463 |
-
"Content-Transfer-Encoding: base64\n\n" .
|
464 |
-
$data . "\n\n" .
|
465 |
-
"--{$mime_boundary}--\n";
|
466 |
|
467 |
-
$ok = mail($email_to, $email_subject, $email_message, $headers);
|
468 |
|
469 |
return $ok;
|
470 |
|
471 |
}
|
472 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
7 |
* License: GNU/GPL
|
8 |
* Email: admin@xcloner.com
|
9 |
* Revision: 1.0
|
10 |
+
* Date: July 2014
|
11 |
**/
|
12 |
|
13 |
+
$topErrorLine1 = "To run this script you need to create a custom config file inside XCloner Config, and call the script using php cli command like this:";
|
14 |
+
$topErrorLine2 = "php ".__FILE__." mycustomconfig.php";
|
15 |
+
|
16 |
+
//if( php_sapi_name() != 'cli' ){
|
17 |
+
if(!isset($argv[1]) ) {
|
18 |
+
echo "<h2>".$topErrorLine1."</h2>\n";
|
19 |
+
echo "<strong>".$topErrorLine2."</strong>\n";
|
20 |
+
exit;
|
21 |
+
}
|
22 |
+
|
23 |
// Set flag that this is a parent file
|
24 |
@error_reporting(E_ALL^E_NOTICE);
|
25 |
@set_time_limit('3600');
|
26 |
define( '_VALID_MOS', 1 );
|
27 |
+
header('Content-Type: text/html; charset=utf-8');
|
28 |
|
29 |
include_once("admin.cloner.html.php");
|
30 |
include_once("cloner.functions.php");
|
31 |
|
32 |
+
$root = dirname(dirname(dirname(dirname(__FILE__))));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
|
34 |
$script_dir = str_replace("\\","/",dirname(__FILE__));
|
35 |
if(is_dir($script_dir)){
|
36 |
+
|
37 |
chdir($script_dir);
|
38 |
|
39 |
}
|
40 |
|
41 |
+
/*accept extra config file only through argv from command line interface*/
|
42 |
+
$_REQUEST['config'] = $argv[1];
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
43 |
|
44 |
//filter the config request path
|
45 |
$_REQUEST['config'] = str_replace(array("..","/","\\"), array("","",""), trim($_REQUEST['config']));
|
46 |
|
47 |
+
if($_REQUEST['config'] != "" and file_exists('./configs/'.$_REQUEST['config'])){
|
48 |
+
|
49 |
require_once( './configs/'.$_REQUEST['config'] );
|
50 |
+
|
51 |
$smsg = "Using configs/".$_REQUEST['config']." as configuration file";
|
52 |
+
|
53 |
}
|
54 |
else{
|
55 |
|
56 |
+
#require_once( './cloner.config.php' );
|
57 |
+
|
58 |
+
logxx($topErrorLine1);
|
59 |
+
logxx($topErrorLine2);
|
60 |
+
|
61 |
+
exit;
|
62 |
+
|
63 |
$smsg = "Using default configuration file";
|
64 |
|
65 |
}
|
69 |
|
70 |
$mosConfig_live_site = $_CONFIG['mosConfig_live_site'];
|
71 |
|
72 |
+
|
73 |
logxx($smsg);
|
74 |
|
75 |
|
87 |
if (file_exists( "language/".$mosConfig_lang.".php" )) {
|
88 |
include_once( "language/".$mosConfig_lang.".php" );
|
89 |
@include_once( "language/english.php" );
|
90 |
+
}
|
91 |
else{
|
92 |
include_once( "language/english.php" );
|
93 |
}
|
94 |
|
95 |
|
96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
$access=1;
|
98 |
$_REQUEST[cron_dbonly] = 0;
|
99 |
$_REQUEST[cron_access] = 1;
|
104 |
|
105 |
if($_CONFIG[cron_bname]!="")
|
106 |
$_REQUEST['bname'] = $_CONFIG[cron_bname];
|
107 |
+
|
108 |
+
|
109 |
function logxx($string = ""){
|
110 |
+
|
111 |
+
global $mail_log;
|
112 |
|
113 |
$return = "<b>$string</b><br />\r\n";
|
114 |
+
|
115 |
$mail_log .= $return;
|
116 |
|
117 |
echo $return;
|
127 |
$f_arr = array(); $f = 0;
|
128 |
$s_arr = array(); $s = 0;
|
129 |
$d_arr[$d] = $_CONFIG['backup_path'];
|
130 |
+
|
|
|
|
|
|
|
|
|
|
|
131 |
|
132 |
if($_CONFIG['cron_btype']==0){
|
133 |
$_REQUEST[dbbackup] = 1;
|
149 |
$GLOBALS['_CONFIG'] = $_CONFIG;
|
150 |
$_REQUEST[cron_dbonly] = 1;
|
151 |
#}
|
152 |
+
|
153 |
logxx("Creating an sql only backup");
|
154 |
$msg = "database backup";
|
155 |
}
|
164 |
logxx("Backup file: ".$source_file);
|
165 |
$bsize = getFileSizeText(filesize($source_file));
|
166 |
|
167 |
+
if($_CONFIG['cron_send']==1)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
168 |
{
|
169 |
+
######################################STARTING FTP TRANSFER##################
|
170 |
+
|
171 |
+
$source_files[] = $source_file;
|
172 |
+
$destination_files[] = $_CONFIG[cron_ftp_path]."/".$file;
|
173 |
+
|
174 |
+
// set up basic connection details
|
175 |
+
list($fhost, $fport) = explode(":",$_CONFIG[cron_ftp_server]);
|
176 |
+
if($fport == "")
|
177 |
+
$fport = '21';
|
178 |
+
|
179 |
+
$ftp_timeout = '3600';
|
180 |
+
|
181 |
+
logxx("Starting ftp transfer:");
|
182 |
+
if(!$_CONFIG[secure_ftp])
|
183 |
+
{
|
184 |
+
// set up basic connection
|
185 |
+
$conn_id = ftp_connect($fhost, (int)$fport, (int)$ftp_timeout);
|
186 |
+
$connect = "Normal";
|
187 |
+
|
188 |
+
// login with username and password
|
189 |
+
$login_result = ftp_login($conn_id, $_CONFIG[cron_ftp_user], $_CONFIG[cron_ftp_pass])
|
190 |
+
or die("Authentification failed when connecting to the ftp server for user ".$_CONFIG[cron_ftp_user]." with pass".$_CONFIG[cron_ftp_pass]);
|
191 |
+
|
192 |
+
// check connection
|
193 |
+
if ((!$conn_id) || (!$login_result)) {
|
194 |
+
echo "<b style='color:red'>FTP connection has failed!</b>";
|
195 |
+
echo "<b style='color:red'>Attempted to connect to ".$_CONFIG[cron_ftp_server]." for user ".$_CONFIG[cron_ftp_user]."</b>";
|
196 |
+
return;
|
197 |
+
} else {
|
198 |
+
#echo "Connected to $_REQUEST[ftp_server], for user $_REQUEST[ftp_user]";
|
199 |
+
}
|
200 |
+
|
201 |
+
if($_CONFIG['system_ftptransfer']==1)
|
202 |
+
{
|
203 |
+
// turn passive mode on
|
204 |
+
@ftp_pasv($conn_id, true);
|
205 |
+
$mode = "Passive";
|
206 |
+
}
|
207 |
+
else
|
208 |
+
{
|
209 |
+
// turn passive mode off
|
210 |
+
@ftp_pasv($conn_id, false);
|
211 |
+
$mode = "Active";
|
212 |
+
}
|
213 |
+
echo "Connected to $connect <b>$_CONFIG[cron_ftp_server] Mode: $mode</b><br />";
|
214 |
+
for($i=0;$i<sizeof($source_files);$i++)
|
215 |
+
{
|
216 |
+
// upload the file
|
217 |
+
$upload = ftp_put($conn_id, $destination_files[$i], $source_files[$i], FTP_BINARY);
|
218 |
+
|
219 |
+
// check upload status
|
220 |
+
if (!$upload) {
|
221 |
+
echo "<b style='color:red'>FTP upload has failed for file $source_files[$i] ! Stopping ....<br /></b>";return;
|
222 |
+
} else {
|
223 |
+
echo "<b>Upload success from file <i>$source_files[$i]</i> <br />to <i>$destination_files[$i]</i> ...<br /></b>";
|
224 |
+
}
|
225 |
+
}
|
226 |
+
|
227 |
+
// close the FTP stream
|
228 |
+
ftp_close($conn_id);
|
229 |
+
}
|
230 |
+
else //Use sftp
|
231 |
+
{
|
232 |
+
//set php path to include required sftp files
|
233 |
+
set_include_path(get_include_path() . PATH_SEPARATOR .'classes/phpseclib');
|
234 |
+
|
235 |
+
include('Net/SFTP.php');
|
236 |
+
//define('NET_SFTP_LOGGING', NET_SFTP_LOG_COMPLEX); // or NET_SFTP_LOG_SIMPLE
|
237 |
+
|
238 |
+
//connect to host and authenticate user
|
239 |
+
$sftp = new Net_SFTP($fhost);
|
240 |
+
if (!$sftp->login($_CONFIG[cron_ftp_user], $_CONFIG[cron_ftp_pass]))
|
241 |
+
{
|
242 |
+
logxx('Login Failed');
|
243 |
+
die("Login Failed");
|
244 |
+
}
|
245 |
+
logxx("Connected to $connect <b>$_CONFIG[cron_ftp_server] Successfully!><br />");
|
246 |
+
|
247 |
+
//transfere files
|
248 |
+
for($i=0;$i<sizeof($source_files);$i++)
|
249 |
+
{
|
250 |
+
// upload the file
|
251 |
+
$upload = $sftp->put($destination_files[$i], $source_files[$i], NET_SFTP_LOCAL_FILE);
|
252 |
+
|
253 |
+
// check upload status
|
254 |
+
if (!$upload) {
|
255 |
+
logxx("<b style='color:red'>FTP upload has failed for file $source_files[$i] ! Stopping ....<br /></b>");return;
|
256 |
+
} else {
|
257 |
+
logxx("<b>Upload success from file <i>$source_files[$i]</i> <br />to <i>$destination_files[$i]</i> ...<br /></b>");
|
258 |
+
}
|
259 |
+
}
|
260 |
+
|
261 |
+
//disconnect from server
|
262 |
+
unset($sftp);
|
263 |
+
}
|
264 |
+
|
265 |
+
logxx("Ftp transfer finished succesfully!");
|
266 |
+
|
267 |
+
if($_CONFIG[cron_ftp_delb]==1)
|
268 |
+
{
|
269 |
+
@unlink($source_file);
|
270 |
+
logxx("Backup succesfully deleted from the original server!");
|
271 |
+
}
|
272 |
+
##############################################################################
|
273 |
}
|
274 |
+
else if($_CONFIG['cron_send']==2)
|
|
|
275 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
276 |
#######################################STARTING Email TRANSFER################
|
277 |
logxx("Sending mail with backup");
|
278 |
|
283 |
Attached is the backup generated on $date
|
284 |
Source Filename: $source_file
|
285 |
Server: $mosConfig_live_site
|
286 |
+
|
287 |
Powered by http://www.xcloner.com - XCloner - Backup and Restore made easy!
|
288 |
</pre>
|
289 |
|
290 |
";
|
291 |
+
|
292 |
$ok = send_mail($mosConfig_mailfrom, "XCloner $msg", $message, $_CONFIG['cron_email_address'], $source_file);
|
293 |
+
|
294 |
#echo mosMail( $mosConfig_mailfrom, $mosConfig_fromname, $_CONFIG['cron_email_address'], "XCloner $msg", $message, $mode, '', '' );
|
295 |
if($ok)
|
296 |
logxx("Mail sent to ".$_CONFIG['cron_email_address']);
|
297 |
else
|
298 |
+
logxx("There was an error in sending the mail cron to ".$_CONFIG['cron_email_address']);
|
299 |
|
300 |
##############################################################################
|
301 |
}
|
309 |
|
310 |
logxx();
|
311 |
|
312 |
+
if(!$_CONFIG['cron_amazon_ssl'])
|
313 |
+
$amazon_ssl = false;
|
314 |
+
else
|
315 |
+
$amazon_ssl = true;
|
316 |
|
317 |
+
$s3 = new S3($_CONFIG['cron_amazon_awsAccessKey'], $_CONFIG['cron_amazon_awsSecretKey'], $amazon_ssl);
|
318 |
+
|
319 |
+
logxx("AMAZON S3: Starting communication with the Amazon S3 server...ssl mode ".(int)$amazon_ssl);
|
320 |
|
321 |
$buckets = $s3->listBuckets();
|
322 |
|
340 |
|
341 |
|
342 |
|
343 |
+
}
|
344 |
+
###### END
|
345 |
+
|
346 |
+
####### STARING DROPBOX MODE
|
347 |
+
if($_CONFIG['cron_dropbox_active']){
|
348 |
+
|
349 |
+
include_once("classes/DropboxClient.php");
|
350 |
+
|
351 |
+
$dropbox = new DropboxClient(array(
|
352 |
+
'app_key' => $_CONFIG['cron_dropbox_Key'],
|
353 |
+
'app_secret' => $_CONFIG['cron_dropbox_Secret'],
|
354 |
+
'app_full_access' => false,
|
355 |
+
),'en');
|
356 |
+
|
357 |
+
logxx();
|
358 |
+
|
359 |
+
logxx("DROPBOX: Starting communication with the DropBox server...");
|
360 |
+
|
361 |
+
// first try to load existing access token
|
362 |
+
$access_token = load_token("access");
|
363 |
+
if(!empty($access_token)) {
|
364 |
+
$dropbox->SetAccessToken($access_token);
|
365 |
+
//print_r($access_token);
|
366 |
+
}
|
367 |
+
elseif(!empty($_GET['auth_callback'])) // are we coming from dropbox's auth page?
|
368 |
+
{
|
369 |
+
// then load our previosly created request token
|
370 |
+
$request_token = load_token($_GET['oauth_token']);
|
371 |
+
if(empty($request_token)) die('Request token not found!');
|
372 |
+
|
373 |
+
// get & store access token, the request token is not needed anymore
|
374 |
+
$access_token = $dropbox->GetAccessToken($request_token);
|
375 |
+
store_token($access_token, "access");
|
376 |
+
delete_token($_GET['oauth_token']);
|
377 |
+
}
|
378 |
+
|
379 |
+
// checks if access token is required
|
380 |
+
if(!$dropbox->IsAuthorized())
|
381 |
+
{
|
382 |
+
// redirect user to dropbox auth page
|
383 |
+
$return_url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."?auth_callback=1";
|
384 |
+
$auth_url = $dropbox->BuildAuthorizeUrl($return_url);
|
385 |
+
$request_token = $dropbox->GetRequestToken();
|
386 |
+
store_token($request_token, $request_token['t']);
|
387 |
+
die("Authentication required. <a href='$auth_url'>Click here.</a>");
|
388 |
+
}
|
389 |
+
|
390 |
+
|
391 |
+
|
392 |
+
$return = $dropbox->UploadFile($clonerPath."/".$file, $_CONFIG['cron_dropbox_dirname']."/".$file);
|
393 |
+
if($return->error)
|
394 |
+
logxx($return->error);
|
395 |
+
else
|
396 |
+
logxx("File copied to ".$return->path);
|
397 |
+
|
398 |
+
#print_r($return);
|
399 |
+
|
400 |
}
|
401 |
###### END
|
402 |
|
414 |
###################END OLDER BACKUPS
|
415 |
|
416 |
$logemail = explode(";", $_CONFIG['cron_logemail']);
|
|
|
417 |
|
418 |
+
if($_CONFIG['cron_fromlogemail'])
|
419 |
+
$fromemail = $_CONFIG['cron_fromlogemail'];
|
420 |
+
else
|
421 |
+
$fromemail = "nobody@noreply.com";
|
422 |
+
|
423 |
+
if(sizeof($logemail)>0){
|
424 |
+
|
425 |
for($i=0; $i<sizeof($logemail);$i++){
|
426 |
+
|
427 |
$email = trim($logemail[$i]);
|
428 |
if($email != ""){
|
429 |
+
|
430 |
$email_subject = "cron log ".time();
|
431 |
+
|
432 |
+
$headers ="From: \"XCloner Cron Log Output\" <".$fromemail.">\n";
|
433 |
|
434 |
if(mail($email, $email_subject, strip_tags($mail_log), $headers)){
|
435 |
+
|
436 |
logxx ("Notification Mail was sent to $email");
|
437 |
+
|
438 |
}
|
439 |
+
|
440 |
+
|
441 |
}
|
442 |
+
|
443 |
}
|
444 |
+
|
445 |
}
|
446 |
|
447 |
logxx("<br />\n\nALL DONE! I will exit now from cron.");
|
463 |
if(is_array($f_arr))
|
464 |
foreach($f_arr as $file)
|
465 |
if(($file!='.')&&($file != '..')){
|
466 |
+
|
467 |
#logxx("Processing backup file $file");
|
468 |
$cfile = $_CONFIG['clonerPath']."/".$file;
|
469 |
+
|
470 |
$filemtime = filemtime($cfile) ;
|
471 |
+
|
472 |
$ftime= $filemtime + $_CONFIG['cron_file_delete']*24*60*60;
|
473 |
+
|
474 |
$ctime = time();
|
475 |
+
|
476 |
if($ftime < $ctime){
|
477 |
+
|
478 |
if(unlink($cfile))
|
479 |
logxx("Deleted backup file $file created on ".date("Y-m-d", $filemtime));
|
480 |
else
|
481 |
logxx("Could not delete backup file $file, please delete it manually");
|
482 |
+
|
483 |
}
|
484 |
+
|
485 |
}
|
486 |
|
487 |
}
|
488 |
|
489 |
function send_mail($email_from, $email_subject, $email_txt, $email_to, $fileatt){
|
490 |
+
$fileatt_type = "application/octet-stream"; // File Type
|
491 |
+
$fileatt_name = basename($fileatt); // Filename that will be used for the file as the attachment
|
492 |
$data = "";
|
493 |
|
494 |
+
$headers = "From: \"Cronbackup XCloner\" <".$email_from.">";
|
495 |
|
496 |
if($fileatt != ""){
|
497 |
+
|
498 |
if($file = @fopen($fileatt,'rb')){
|
499 |
+
|
500 |
$data = fread($file,filesize($fileatt));
|
501 |
+
|
502 |
fclose($file);
|
503 |
|
504 |
+
}
|
505 |
else{
|
506 |
logxx("Unable to open file $fileatt");
|
507 |
}
|
508 |
|
509 |
}
|
510 |
|
511 |
+
$semi_rand = md5(time());
|
512 |
+
$mime_boundary = "==Multipart_Boundary_x{$semi_rand}x";
|
513 |
+
|
514 |
+
$headers .= "\nMIME-Version: 1.0\n" .
|
515 |
+
"Content-Type: multipart/mixed;\n" .
|
516 |
+
" boundary=\"{$mime_boundary}\"";
|
517 |
|
518 |
+
$email_message .= "This is a multi-part message in MIME format.\n\n" .
|
519 |
+
"--{$mime_boundary}\n" .
|
520 |
+
"Content-Type:text/html; charset=\"iso-8859-1\"\n" .
|
521 |
+
"Content-Transfer-Encoding: 7bit\n\n" .
|
522 |
+
$email_txt . "\n\n";
|
523 |
|
524 |
+
$data = chunk_split(base64_encode($data));
|
525 |
|
526 |
+
$email_message .= "--{$mime_boundary}\n" .
|
527 |
+
"Content-Type: {$fileatt_type};\n" .
|
528 |
+
" name=\"{$fileatt_name}\"\n" .
|
529 |
+
//"Content-Disposition: attachment;\n" .
|
530 |
+
//" filename=\"{$fileatt_name}\"\n" .
|
531 |
+
"Content-Transfer-Encoding: base64\n\n" .
|
532 |
+
$data . "\n\n" .
|
533 |
+
"--{$mime_boundary}--\n";
|
534 |
|
535 |
+
$ok = mail($email_to, $email_subject, $email_message, $headers);
|
536 |
|
537 |
return $ok;
|
538 |
|
539 |
}
|
540 |
+
?>
|
541 |
+
<?php
|
542 |
+
function store_token($token, $name)
|
543 |
+
{
|
544 |
+
if(!file_put_contents("tokens/$name.token", serialize($token)))
|
545 |
+
die('<br />Could not store token! <b>Make sure that the directory `tokens` exists and is writable!</b>');
|
546 |
+
}
|
547 |
+
|
548 |
+
function load_token($name)
|
549 |
+
{
|
550 |
+
if(!file_exists("tokens/$name.token")) return null;
|
551 |
+
return @unserialize(@file_get_contents("tokens/$name.token"));
|
552 |
+
}
|
553 |
+
|
554 |
+
function delete_token($name)
|
555 |
+
{
|
556 |
+
@unlink("tokens/$name.token");
|
557 |
+
}
|
cloner.functions.php
CHANGED
@@ -49,7 +49,7 @@
|
|
49 |
*/
|
50 |
function E_print($message)
|
51 |
{
|
52 |
-
print "<
|
53 |
}
|
54 |
|
55 |
/*
|
@@ -112,6 +112,8 @@
|
|
112 |
/*Simple redirect function*/
|
113 |
function mosRedirect($url, $msg = "")
|
114 |
{
|
|
|
|
|
115 |
echo "<script type=\"text/javascript\">
|
116 |
|
117 |
window.location = \"$url&mosmsg=" . urlencode($msg) . "\";
|
@@ -123,7 +125,8 @@
|
|
123 |
|
124 |
function fdefault()
|
125 |
{
|
126 |
-
HTML_cloner
|
|
|
127 |
}
|
128 |
|
129 |
function config($option)
|
@@ -132,31 +135,32 @@
|
|
132 |
|
133 |
|
134 |
if (@$_REQUEST['action'] == 'save') {
|
135 |
-
|
|
|
|
|
136 |
$databases_incl_list = "";
|
|
|
137 |
if (is_array($_REQUEST['databases_incl']))
|
138 |
foreach ($_REQUEST['databases_incl'] as $database) {
|
139 |
$databases_incl_list .= $database . ",";
|
140 |
}
|
141 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
$cfg = '<?' . 'php' . "\n";
|
143 |
|
144 |
$cfg .= '$_CONFIG[\'license_code\']=\'' . $_REQUEST[license_code] . '\';' . "\n";
|
145 |
-
|
146 |
$cfg .= '$_CONFIG[\'backup_path\']="' . $_REQUEST[backup_path] . '";' . "\n";
|
147 |
|
148 |
$cfg .= '$_CONFIG[\'clonerPath\']="' . $_REQUEST[clonerPath] . '";' . "\n";
|
149 |
|
150 |
-
$cfg .= '$_CONFIG[\'jcuser\']=\'' . $_REQUEST[jcuser] . '\';' . "\n";
|
151 |
-
|
152 |
-
if ($_REQUEST['jcpass'] == '') {
|
153 |
-
$jcpass = $_CONFIG['jcpass'];
|
154 |
-
} else {
|
155 |
-
|
156 |
-
|
157 |
-
$jcpass = md5($_REQUEST['jcpass']);
|
158 |
-
}
|
159 |
-
|
160 |
$cfg .= '$_CONFIG[\'jcpass\']=\'' . $jcpass . '\';' . "\n";
|
161 |
|
162 |
$cfg .= '$_CONFIG[\'mysql_host\']="' . $_REQUEST[mysql_host] . '";' . "\n";
|
@@ -252,15 +256,25 @@
|
|
252 |
$cfg .= '$_CONFIG[\'cron_amazon_bucket\']=\'' . $_REQUEST[cron_amazon_bucket] . '\';' . "\n";
|
253 |
|
254 |
$cfg .= '$_CONFIG[\'cron_amazon_dirname\']=\'' . $_REQUEST[cron_amazon_dirname] . '\';' . "\n";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
255 |
|
256 |
$cfg .= '$_CONFIG[\'debug\']="' . $_REQUEST[debug] . '";' . "\n";
|
257 |
|
258 |
|
259 |
$cfg .= '?' . '>';
|
260 |
|
261 |
-
fwrite($fp, $cfg);
|
262 |
|
263 |
-
fclose($fp);
|
264 |
|
265 |
$msg = LM_MSG_BACK_1;
|
266 |
|
@@ -281,12 +295,15 @@
|
|
281 |
|
282 |
//exit;
|
283 |
mosRedirect('index2.php?option=' . $option . "&task=config", $msg);
|
284 |
-
} else {
|
285 |
$msg = "<font color='red'>ERROR... Unable to write to ".realpath($config_file).", please make it writeable!</font>";
|
286 |
E_print($msg);
|
287 |
-
}
|
|
|
|
|
288 |
}
|
289 |
-
HTML_cloner
|
|
|
290 |
}
|
291 |
|
292 |
//## JoomlaCloner Language Manager
|
@@ -312,7 +329,8 @@
|
|
312 |
mosRedirect('index2.php?option=' . $option . "&task=lang", $msg);
|
313 |
}
|
314 |
|
315 |
-
HTML_cloner
|
|
|
316 |
}
|
317 |
|
318 |
function translator_add($option, $task)
|
@@ -338,9 +356,9 @@
|
|
338 |
|
339 |
mosRedirect('index2.php?option=' . $option . "&task=lang", $msg);
|
340 |
}
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
}
|
345 |
function translator_edit($option, $task)
|
346 |
{
|
@@ -422,14 +440,15 @@
|
|
422 |
|
423 |
|
424 |
if ($lang == 'english') {
|
425 |
-
|
|
|
426 |
} else {
|
427 |
$def_data = get_lang_data($dfile);
|
428 |
$cur_data = get_lang_data($file);
|
429 |
|
430 |
$data = array_merge($def_data, $cur_data);
|
431 |
-
|
432 |
-
|
433 |
}
|
434 |
}
|
435 |
|
@@ -644,7 +663,8 @@
|
|
644 |
getBackupFiles($d_arr, $f_arr, $s_arr, $d, $f);
|
645 |
|
646 |
// load presentation layer
|
647 |
-
|
|
|
648 |
}
|
649 |
|
650 |
function moveBackup($option)
|
@@ -660,8 +680,10 @@
|
|
660 |
if ($_REQUEST['action'] == "connect") {
|
661 |
$ret = start_connect($_REQUEST[files]);
|
662 |
}
|
663 |
-
if (!$ret)
|
664 |
-
|
|
|
|
|
665 |
}
|
666 |
|
667 |
function start_connect($files)
|
@@ -672,10 +694,10 @@
|
|
672 |
if (($_REQUEST[task] == 'move') || ($_REQUEST[task2] == 'move')) {
|
673 |
} else {
|
674 |
|
675 |
-
$source_file[0] = "restore/XCloner.php";
|
676 |
$destination_file[0] = $_REQUEST[ftp_dir] . "/XCloner.php";
|
677 |
|
678 |
-
$source_file[1] = "restore/TAR.php";
|
679 |
$destination_file[1] = $_REQUEST[ftp_dir] . "/TAR.php";
|
680 |
}
|
681 |
|
@@ -830,7 +852,7 @@
|
|
830 |
return 1;
|
831 |
} else {
|
832 |
|
833 |
-
echo "<br><br><h2>" . LM_MSG_BACK_4 . " <br /><a href='" . $redurl . "'>click here to continue...</a></h2>";
|
834 |
return 1;
|
835 |
}
|
836 |
|
@@ -893,8 +915,8 @@
|
|
893 |
}
|
894 |
|
895 |
|
896 |
-
|
897 |
-
|
898 |
}
|
899 |
function downloadBackup($file)
|
900 |
{
|
@@ -1023,9 +1045,10 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
|
|
1023 |
}
|
1024 |
|
1025 |
// load presentation layer
|
1026 |
-
if ($option != 'nohtml')
|
1027 |
-
|
1028 |
-
|
|
|
1029 |
return $d_arr;
|
1030 |
}
|
1031 |
|
@@ -1087,7 +1110,7 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
|
|
1087 |
}
|
1088 |
|
1089 |
|
1090 |
-
$url = "
|
1091 |
|
1092 |
if ($endf >= $lines)
|
1093 |
$endf = $lines;
|
@@ -1339,14 +1362,14 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
|
|
1339 |
foreach ($databases_incl as $database_name)
|
1340 |
if ($database_name != '') {
|
1341 |
$excltables = "";
|
1342 |
-
|
1343 |
|
1344 |
$sql_file[] = doBackup($tables, 'sql', 'local', 'both', $_SERVER['HTTP_USER_AGENT'], $_CONFIG['backups_dir'], $databaseResult_incl, $database_name, $excltables, $database_name);
|
1345 |
|
1346 |
$databaseResult .= "<br /> <b>$database_name:</b> " . $databaseResult_incl;
|
1347 |
}
|
1348 |
|
1349 |
-
|
1350 |
}
|
1351 |
} else {
|
1352 |
#$databaseResult = LM_DATABASE_EXCLUDED;
|
@@ -1542,8 +1565,8 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
|
|
1542 |
// echo "Starting the manual backup process!<br />";
|
1543 |
if((!$_CONFIG['refresh_mode']) and ($_CONFIG['enable_db_backup']))
|
1544 |
echo "<h2>Database backup: </h2>" . $databaseResult . "<br /><br />";
|
1545 |
-
|
1546 |
-
|
1547 |
return;
|
1548 |
}
|
1549 |
|
@@ -1635,8 +1658,8 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
|
|
1635 |
E_print("Backup failed, please check your tar server utility support!");
|
1636 |
return;
|
1637 |
}*/
|
1638 |
-
|
1639 |
-
|
1640 |
|
1641 |
return;
|
1642 |
}
|
@@ -1678,11 +1701,12 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
|
|
1678 |
|
1679 |
// load presentation layer
|
1680 |
if ($option != 'nohtml') {
|
1681 |
-
|
|
|
1682 |
} else {
|
1683 |
|
1684 |
-
|
1685 |
-
logxx(
|
1686 |
}
|
1687 |
|
1688 |
if (is_array($databases_incl)) {
|
@@ -1706,7 +1730,8 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
|
|
1706 |
// ----------------------------------------------------------
|
1707 |
|
1708 |
// load presentation layer
|
1709 |
-
HTML_cloner
|
|
|
1710 |
}
|
1711 |
|
1712 |
|
@@ -1916,8 +1941,8 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
|
|
1916 |
|
1917 |
if ($tables[0] == "all") {
|
1918 |
array_pop($tables);
|
1919 |
-
$query =
|
1920 |
-
while ($row =
|
1921 |
$tables_list[] = $row[0];
|
1922 |
}
|
1923 |
|
@@ -1969,19 +1994,19 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
|
|
1969 |
}
|
1970 |
|
1971 |
/*Added some default values for quotes and auto_increment problems*/
|
1972 |
-
|
1973 |
-
|
1974 |
|
1975 |
if ($_REQUEST['dbbackup_comp']) {
|
1976 |
-
|
1977 |
}
|
1978 |
|
1979 |
|
1980 |
/* Store the "Create Tables" SQL in variable $CreateTable[$tblval] */
|
1981 |
if ($toBackUp != "data") {
|
1982 |
foreach ($tables as $tblval) {
|
1983 |
-
$query =
|
1984 |
-
$row =
|
1985 |
$CreateTable[$tblval] = $row[1];
|
1986 |
}
|
1987 |
}
|
@@ -1989,8 +2014,8 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
|
|
1989 |
/* Store all the FIELD TYPES being backed-up (text fields need to be delimited) in variable $FieldType*/
|
1990 |
if ($toBackUp != "structure") {
|
1991 |
foreach ($tables as $tblval) {
|
1992 |
-
$query =
|
1993 |
-
while ($row =
|
1994 |
$fields[] = $row[0];
|
1995 |
}
|
1996 |
foreach ($fields as $field) {
|
@@ -2043,15 +2068,15 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
|
|
2043 |
|
2044 |
if ($toBackUp != "structure") {
|
2045 |
$OutBuffer .= "#\n# Dumping data for table `$tblval`\n#\n";
|
2046 |
-
$query =
|
2047 |
|
2048 |
-
while ($row =
|
2049 |
$InsertDump = "INSERT INTO `$tblval` VALUES (";
|
2050 |
$arr = $row;
|
2051 |
foreach ($arr as $key => $value) {
|
2052 |
-
$value =
|
2053 |
-
|
2054 |
-
|
2055 |
//if (@preg_match ("/\b" . $FieldType[$tblval][$key] . "\b/i", "DATE TIME DATETIME CHAR VARCHAR TEXT TINYTEXT MEDIUMTEXT LONGTEXT BLOB TINYBLOB MEDIUMBLOB LONGBLOB ENUM SET"))
|
2056 |
{
|
2057 |
$InsertDump .= "'$value',";
|
@@ -2118,8 +2143,11 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
|
|
2118 |
|
2119 |
function getVersion()
|
2120 |
{
|
2121 |
-
|
2122 |
-
|
2123 |
-
|
|
|
|
|
|
|
2124 |
}
|
2125 |
?>
|
49 |
*/
|
50 |
function E_print($message)
|
51 |
{
|
52 |
+
print "<div id='message' class='error'>$message</div>";
|
53 |
}
|
54 |
|
55 |
/*
|
112 |
/*Simple redirect function*/
|
113 |
function mosRedirect($url, $msg = "")
|
114 |
{
|
115 |
+
|
116 |
+
$url = str_replace("index2.php", "plugins.php?page=xcloner_show&", $url);
|
117 |
echo "<script type=\"text/javascript\">
|
118 |
|
119 |
window.location = \"$url&mosmsg=" . urlencode($msg) . "\";
|
125 |
|
126 |
function fdefault()
|
127 |
{
|
128 |
+
$html = new HTML_cloner();
|
129 |
+
$html->_FDefault();
|
130 |
}
|
131 |
|
132 |
function config($option)
|
135 |
|
136 |
|
137 |
if (@$_REQUEST['action'] == 'save') {
|
138 |
+
|
139 |
+
$msg = LM_MSG_BACK_1;
|
140 |
+
|
141 |
$databases_incl_list = "";
|
142 |
+
|
143 |
if (is_array($_REQUEST['databases_incl']))
|
144 |
foreach ($_REQUEST['databases_incl'] as $database) {
|
145 |
$databases_incl_list .= $database . ",";
|
146 |
}
|
147 |
+
foreach($_REQUEST as $key=>$value)
|
148 |
+
update_site_option( "xcloner_".$key, $value, '', 'yes' );
|
149 |
+
|
150 |
+
//Additional radio options
|
151 |
+
update_site_option ("xcloner_mem", $_REQUEST["mem"], '', 'yes');
|
152 |
+
update_site_option ("xcloner_sql_mem", $_REQUEST["sql_mem"], '', 'yes');
|
153 |
+
|
154 |
+
#if ($fp = @fopen($config_file, 'w'))
|
155 |
+
if(1){
|
156 |
$cfg = '<?' . 'php' . "\n";
|
157 |
|
158 |
$cfg .= '$_CONFIG[\'license_code\']=\'' . $_REQUEST[license_code] . '\';' . "\n";
|
159 |
+
|
160 |
$cfg .= '$_CONFIG[\'backup_path\']="' . $_REQUEST[backup_path] . '";' . "\n";
|
161 |
|
162 |
$cfg .= '$_CONFIG[\'clonerPath\']="' . $_REQUEST[clonerPath] . '";' . "\n";
|
163 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
164 |
$cfg .= '$_CONFIG[\'jcpass\']=\'' . $jcpass . '\';' . "\n";
|
165 |
|
166 |
$cfg .= '$_CONFIG[\'mysql_host\']="' . $_REQUEST[mysql_host] . '";' . "\n";
|
256 |
$cfg .= '$_CONFIG[\'cron_amazon_bucket\']=\'' . $_REQUEST[cron_amazon_bucket] . '\';' . "\n";
|
257 |
|
258 |
$cfg .= '$_CONFIG[\'cron_amazon_dirname\']=\'' . $_REQUEST[cron_amazon_dirname] . '\';' . "\n";
|
259 |
+
|
260 |
+
$cfg .= '$_CONFIG[\'cron_amazon_ssl\']=\'' . $_REQUEST[cron_amazon_ssl] . '\';' . "\n";
|
261 |
+
|
262 |
+
$cfg .= '$_CONFIG[\'cron_dropbox_active\']=\'' . $_REQUEST[cron_dropbox_active] . '\';' . "\n";
|
263 |
+
|
264 |
+
$cfg .= '$_CONFIG[\'cron_dropbox_Key\']=\'' . $_REQUEST[cron_dropbox_Key] . '\';' . "\n";
|
265 |
+
|
266 |
+
$cfg .= '$_CONFIG[\'cron_dropbox_Secret\']=\'' . $_REQUEST[cron_dropbox_Secret] . '\';' . "\n";
|
267 |
+
|
268 |
+
$cfg .= '$_CONFIG[\'cron_dropbox_dirname\']=\'' . $_REQUEST[cron_dropbox_dirname] . '\';' . "\n";
|
269 |
|
270 |
$cfg .= '$_CONFIG[\'debug\']="' . $_REQUEST[debug] . '";' . "\n";
|
271 |
|
272 |
|
273 |
$cfg .= '?' . '>';
|
274 |
|
275 |
+
#fwrite($fp, $cfg);
|
276 |
|
277 |
+
#fclose($fp);
|
278 |
|
279 |
$msg = LM_MSG_BACK_1;
|
280 |
|
295 |
|
296 |
//exit;
|
297 |
mosRedirect('index2.php?option=' . $option . "&task=config", $msg);
|
298 |
+
} /*else {
|
299 |
$msg = "<font color='red'>ERROR... Unable to write to ".realpath($config_file).", please make it writeable!</font>";
|
300 |
E_print($msg);
|
301 |
+
}*/
|
302 |
+
|
303 |
+
mosRedirect('index2.php?option=' . $option . "&task=config", $msg);
|
304 |
}
|
305 |
+
$html = new HTML_cloner();
|
306 |
+
$html->Config($option);
|
307 |
}
|
308 |
|
309 |
//## JoomlaCloner Language Manager
|
329 |
mosRedirect('index2.php?option=' . $option . "&task=lang", $msg);
|
330 |
}
|
331 |
|
332 |
+
$html = new HTML_cloner();
|
333 |
+
$html->Translator($option, $lang_array);
|
334 |
}
|
335 |
|
336 |
function translator_add($option, $task)
|
356 |
|
357 |
mosRedirect('index2.php?option=' . $option . "&task=lang", $msg);
|
358 |
}
|
359 |
+
|
360 |
+
$html = new HTML_cloner();
|
361 |
+
$html->Translator_Add($option);
|
362 |
}
|
363 |
function translator_edit($option, $task)
|
364 |
{
|
440 |
|
441 |
|
442 |
if ($lang == 'english') {
|
443 |
+
$html = new HTML_cloner();
|
444 |
+
$html->Translator_Edit_DEFAULT($option, $content, $file, $lang);
|
445 |
} else {
|
446 |
$def_data = get_lang_data($dfile);
|
447 |
$cur_data = get_lang_data($file);
|
448 |
|
449 |
$data = array_merge($def_data, $cur_data);
|
450 |
+
$html = new HTML_cloner();
|
451 |
+
$html->Translator_Edit($option, $data, $def_data, $file, $lang);
|
452 |
}
|
453 |
}
|
454 |
|
663 |
getBackupFiles($d_arr, $f_arr, $s_arr, $d, $f);
|
664 |
|
665 |
// load presentation layer
|
666 |
+
$html = new HTML_cloner();
|
667 |
+
$html->showBackups($f_arr, $s_arr, $_CONFIG['clonerPath'], $option);
|
668 |
}
|
669 |
|
670 |
function moveBackup($option)
|
680 |
if ($_REQUEST['action'] == "connect") {
|
681 |
$ret = start_connect($_REQUEST[files]);
|
682 |
}
|
683 |
+
if (!$ret){
|
684 |
+
$html = new HTML_cloner();
|
685 |
+
$html->TransferForm($option, $files_out);
|
686 |
+
}
|
687 |
}
|
688 |
|
689 |
function start_connect($files)
|
694 |
if (($_REQUEST[task] == 'move') || ($_REQUEST[task2] == 'move')) {
|
695 |
} else {
|
696 |
|
697 |
+
$source_file[0] = __XCLONERDIR__ ."/restore/XCloner.php";
|
698 |
$destination_file[0] = $_REQUEST[ftp_dir] . "/XCloner.php";
|
699 |
|
700 |
+
$source_file[1] = __XCLONERDIR__ ."/restore/TAR.php";
|
701 |
$destination_file[1] = $_REQUEST[ftp_dir] . "/TAR.php";
|
702 |
}
|
703 |
|
852 |
return 1;
|
853 |
} else {
|
854 |
|
855 |
+
echo "<br><br><h2>" . LM_MSG_BACK_4 . " <br /><a target='_blank' href='" . $redurl . "'>click here to continue...</a></h2>";
|
856 |
return 1;
|
857 |
}
|
858 |
|
915 |
}
|
916 |
|
917 |
|
918 |
+
$html = new HTML_cloner();
|
919 |
+
$html->rename($files, $option);
|
920 |
}
|
921 |
function downloadBackup($file)
|
922 |
{
|
1045 |
}
|
1046 |
|
1047 |
// load presentation layer
|
1048 |
+
if ($option != 'nohtml'){
|
1049 |
+
$html = new HTML_cloner();
|
1050 |
+
$html->confirmBackups($d_arr, $ds_arr, $_CONFIG['clonerPath'], $option);
|
1051 |
+
}else
|
1052 |
return $d_arr;
|
1053 |
}
|
1054 |
|
1110 |
}
|
1111 |
|
1112 |
|
1113 |
+
$url = "plugins.php?page=xcloner_show&option=com_cloner&task=refresh&json=$json&startf=$endf&lines=$lines&backup=$backup_filename&excl_manual=" . $_REQUEST['excl_manual'];
|
1114 |
|
1115 |
if ($endf >= $lines)
|
1116 |
$endf = $lines;
|
1362 |
foreach ($databases_incl as $database_name)
|
1363 |
if ($database_name != '') {
|
1364 |
$excltables = "";
|
1365 |
+
$_CONFIG['mysqli']->query("USE $database_name");
|
1366 |
|
1367 |
$sql_file[] = doBackup($tables, 'sql', 'local', 'both', $_SERVER['HTTP_USER_AGENT'], $_CONFIG['backups_dir'], $databaseResult_incl, $database_name, $excltables, $database_name);
|
1368 |
|
1369 |
$databaseResult .= "<br /> <b>$database_name:</b> " . $databaseResult_incl;
|
1370 |
}
|
1371 |
|
1372 |
+
$_CONFIG['mysqli']->query("USE " . $_CONFIG['mysql_database']);
|
1373 |
}
|
1374 |
} else {
|
1375 |
#$databaseResult = LM_DATABASE_EXCLUDED;
|
1565 |
// echo "Starting the manual backup process!<br />";
|
1566 |
if((!$_CONFIG['refresh_mode']) and ($_CONFIG['enable_db_backup']))
|
1567 |
echo "<h2>Database backup: </h2>" . $databaseResult . "<br /><br />";
|
1568 |
+
$html = new HTML_cloner();
|
1569 |
+
$html->goRefreshHtml($filename, $perm_lines, $excl_manual);
|
1570 |
return;
|
1571 |
}
|
1572 |
|
1658 |
E_print("Backup failed, please check your tar server utility support!");
|
1659 |
return;
|
1660 |
}*/
|
1661 |
+
$html = new HTML_cloner();
|
1662 |
+
$html->goRefreshHtml($filename, $perm_lines, $excl_manual);
|
1663 |
|
1664 |
return;
|
1665 |
}
|
1701 |
|
1702 |
// load presentation layer
|
1703 |
if ($option != 'nohtml') {
|
1704 |
+
$html = new HTML_cloner();
|
1705 |
+
$html->generateBackup($filename1, $archiveSize, $originalSize, $mdir, $f, $databaseResult, $option);
|
1706 |
} else {
|
1707 |
|
1708 |
+
$html = new HTML_cloner();
|
1709 |
+
logxx($html->generateBackup_text($filename1, $archiveSize, $originalSize, $mdir, $f, $databaseResult, $option));
|
1710 |
}
|
1711 |
|
1712 |
if (is_array($databases_incl)) {
|
1730 |
// ----------------------------------------------------------
|
1731 |
|
1732 |
// load presentation layer
|
1733 |
+
$html = new HTML_cloner();
|
1734 |
+
$html->showHelp($option);
|
1735 |
}
|
1736 |
|
1737 |
|
1941 |
|
1942 |
if ($tables[0] == "all") {
|
1943 |
array_pop($tables);
|
1944 |
+
$query = $_CONFIG['mysqli']->query("SHOW tables");
|
1945 |
+
while ($row = $query->fetch_array()) {
|
1946 |
$tables_list[] = $row[0];
|
1947 |
}
|
1948 |
|
1994 |
}
|
1995 |
|
1996 |
/*Added some default values for quotes and auto_increment problems*/
|
1997 |
+
$_CONFIG['mysqli']->query("SET SQL_QUOTE_SHOW_CREATE=1;");
|
1998 |
+
$_CONFIG['mysqli']->query("SET sql_mode = 0;");
|
1999 |
|
2000 |
if ($_REQUEST['dbbackup_comp']) {
|
2001 |
+
$_CONFIG['mysqli']->query("SET sql_mode=" . $_REQUEST['dbbackup_comp'] . ";");
|
2002 |
}
|
2003 |
|
2004 |
|
2005 |
/* Store the "Create Tables" SQL in variable $CreateTable[$tblval] */
|
2006 |
if ($toBackUp != "data") {
|
2007 |
foreach ($tables as $tblval) {
|
2008 |
+
$query = $_CONFIG['mysqli']->query("SHOW CREATE table `$tblval`");
|
2009 |
+
$row = $query->fetch_array();
|
2010 |
$CreateTable[$tblval] = $row[1];
|
2011 |
}
|
2012 |
}
|
2014 |
/* Store all the FIELD TYPES being backed-up (text fields need to be delimited) in variable $FieldType*/
|
2015 |
if ($toBackUp != "structure") {
|
2016 |
foreach ($tables as $tblval) {
|
2017 |
+
$query = $_CONFIG['mysqli']->query("SHOW FIELDS FROM `$tblval`");
|
2018 |
+
while ($row = $query->fetch_row()) {
|
2019 |
$fields[] = $row[0];
|
2020 |
}
|
2021 |
foreach ($fields as $field) {
|
2068 |
|
2069 |
if ($toBackUp != "structure") {
|
2070 |
$OutBuffer .= "#\n# Dumping data for table `$tblval`\n#\n";
|
2071 |
+
$query = @$_CONFIG['mysqli']->query("SELECT * FROM `$tblval`");
|
2072 |
|
2073 |
+
while ($row = @$query->fetch_array(MYSQL_ASSOC)) {
|
2074 |
$InsertDump = "INSERT INTO `$tblval` VALUES (";
|
2075 |
$arr = $row;
|
2076 |
foreach ($arr as $key => $value) {
|
2077 |
+
$value = $_CONFIG['mysqli']->real_escape_string($value);
|
2078 |
+
#$value = str_replace("\n", '\r\n', $value);
|
2079 |
+
#$value = str_replace("\r", '', $value);
|
2080 |
//if (@preg_match ("/\b" . $FieldType[$tblval][$key] . "\b/i", "DATE TIME DATETIME CHAR VARCHAR TEXT TINYTEXT MEDIUMTEXT LONGTEXT BLOB TINYBLOB MEDIUMBLOB LONGBLOB ENUM SET"))
|
2081 |
{
|
2082 |
$InsertDump .= "'$value',";
|
2143 |
|
2144 |
function getVersion()
|
2145 |
{
|
2146 |
+
global $_CONFIG;
|
2147 |
+
|
2148 |
+
$query = $_CONFIG['mysqli']->query("SELECT version()");
|
2149 |
+
$row = $query->fetch_array();
|
2150 |
+
|
2151 |
+
return $row[0];
|
2152 |
}
|
2153 |
?>
|
common.php
CHANGED
@@ -30,18 +30,14 @@ if ((!extension_loaded('zlib')) &&(function_exists('ob_start'))) {
|
|
30 |
|
31 |
####################################
|
32 |
|
33 |
-
$_CONFIG['multiple_config_dir'] = "configs";
|
34 |
-
//$strlen = strlen($_CONFIG['backup_path']);
|
35 |
-
//if((substr($_CONFIG['backup_path'], $strlen-1, $strlen) != '/') && (substr($_CONFIG['backup_path'], $strlen-1, $strlen) != '\\'))
|
36 |
-
// $_CONFIG['backup_path'] .= "/";
|
37 |
|
38 |
-
$_CONFIG['backup_path'] =
|
39 |
-
$_CONFIG['backups_dir'] =
|
40 |
|
41 |
$_CONFIG['backup_path'] = str_replace("\\","/", $_CONFIG['backup_path']);
|
42 |
$_CONFIG['backups_dir'] = str_replace("\\","/", $_CONFIG['backups_dir']);
|
43 |
|
44 |
-
|
45 |
$_CONFIG['exfile'] = $_CONFIG['backups_dir']."/.excl";
|
46 |
$_CONFIG['exfile_tar'] = $_CONFIG['backups_dir']."/.excl_tar";
|
47 |
|
@@ -50,19 +46,31 @@ $_CONFIG['commentsfile'] = $_CONFIG['backups_dir']."/.comments"; #$_REQUEST['bac
|
|
50 |
|
51 |
$_CONFIG['script_path'] = str_replace("\\","/",dirname(__FILE__));
|
52 |
|
53 |
-
$lang_dir = "language";
|
54 |
|
55 |
$task = $_REQUEST['task'];
|
56 |
####################################
|
57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
|
59 |
-
if($_CONFIG['enable_db_backup']){
|
60 |
-
|
61 |
-
### Connecting to the mysql server
|
62 |
-
$link = @mysql_connect($_CONFIG['mysql_host'], $_CONFIG['mysql_user'], $_CONFIG['mysql_pass']) or
|
63 |
-
E_print("Could not connect: " . mysql_error());
|
64 |
-
@mysql_select_db($_CONFIG['mysql_database']) or E_print("Unable to select database ".$_CONFIG['mysql_database']);
|
65 |
-
@mysql_query("SET NAMES 'utf8'");
|
66 |
}
|
67 |
|
68 |
|
@@ -71,17 +79,17 @@ if($_CONFIG['select_lang']!="")
|
|
71 |
|
72 |
$mosConfig_lang = $_CONFIG['select_lang'];
|
73 |
|
74 |
-
if (file_exists( "language/".$mosConfig_lang.".php" )) {
|
75 |
|
76 |
-
include_once( "language/".$mosConfig_lang.".php" );
|
77 |
|
78 |
-
@include_once( "language/english.php" );
|
79 |
|
80 |
}
|
81 |
|
82 |
else{
|
83 |
|
84 |
-
include_once( "language/english.php" );
|
85 |
|
86 |
}
|
87 |
|
@@ -98,4 +106,6 @@ $_CONFIG['backup_start_path'] = $_CONFIG['backup_path'];
|
|
98 |
$_CONFIG['backup_store_path'] = $_CONFIG['clonerPath'];
|
99 |
$_CONFIG['temp_dir'] = $_CONFIG['backups_dir'];
|
100 |
|
|
|
|
|
101 |
?>
|
30 |
|
31 |
####################################
|
32 |
|
33 |
+
$_CONFIG['multiple_config_dir'] = __XCLONERDIR__."/configs";
|
|
|
|
|
|
|
34 |
|
35 |
+
$_CONFIG['backup_path'] = ($_CONFIG['backup_path']);
|
36 |
+
$_CONFIG['backups_dir'] = str_replace("//administrator","/administrator",($_CONFIG['backup_path'])."/administrator/backups");
|
37 |
|
38 |
$_CONFIG['backup_path'] = str_replace("\\","/", $_CONFIG['backup_path']);
|
39 |
$_CONFIG['backups_dir'] = str_replace("\\","/", $_CONFIG['backups_dir']);
|
40 |
|
|
|
41 |
$_CONFIG['exfile'] = $_CONFIG['backups_dir']."/.excl";
|
42 |
$_CONFIG['exfile_tar'] = $_CONFIG['backups_dir']."/.excl_tar";
|
43 |
|
46 |
|
47 |
$_CONFIG['script_path'] = str_replace("\\","/",dirname(__FILE__));
|
48 |
|
49 |
+
$lang_dir = __XCLONERDIR__."/language";
|
50 |
|
51 |
$task = $_REQUEST['task'];
|
52 |
####################################
|
53 |
|
54 |
+
if(!class_exists("mysqli")){
|
55 |
+
E_print("mysqli php module is not supported, mysql backup will be disabled. Please reinstall or upgrade php to support the mysqli extension.");
|
56 |
+
$_CONFIG['enable_db_backup'] = 0;
|
57 |
+
}
|
58 |
+
|
59 |
+
if($_CONFIG['enable_db_backup'] and !$_REQUEST['nohtml']){
|
60 |
+
|
61 |
+
### Connecting to the mysql server
|
62 |
+
$_CONFIG['mysqli'] = new mysqli($_CONFIG['mysql_host'], $_CONFIG['mysql_user'], $_CONFIG['mysql_pass'], $_CONFIG['mysql_database']) ;
|
63 |
+
|
64 |
+
if (mysqli_connect_errno()) {
|
65 |
+
E_print("Connect failed: %s\n", mysqli_connect_error());
|
66 |
+
//exit();
|
67 |
+
$_CONFIG['disable_mysql'] = 1;
|
68 |
+
$_CONFIG['enable_db_backup'] = 0;
|
69 |
+
}
|
70 |
+
else{
|
71 |
+
$_CONFIG['mysqli']->query("SET NAMES 'utf8'");
|
72 |
+
}
|
73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
}
|
75 |
|
76 |
|
79 |
|
80 |
$mosConfig_lang = $_CONFIG['select_lang'];
|
81 |
|
82 |
+
if (file_exists( __XCLONERDIR__ ."/language/".$mosConfig_lang.".php" )) {
|
83 |
|
84 |
+
include_once( __XCLONERDIR__ ."/language/".$mosConfig_lang.".php" );
|
85 |
|
86 |
+
@include_once( __XCLONERDIR__ ."/language/english.php" );
|
87 |
|
88 |
}
|
89 |
|
90 |
else{
|
91 |
|
92 |
+
include_once( __XCLONERDIR__ ."language/english.php" );
|
93 |
|
94 |
}
|
95 |
|
106 |
$_CONFIG['backup_store_path'] = $_CONFIG['clonerPath'];
|
107 |
$_CONFIG['temp_dir'] = $_CONFIG['backups_dir'];
|
108 |
|
109 |
+
date_default_timezone_set('America/Los_Angeles');
|
110 |
+
|
111 |
?>
|
configs/.htaccess
ADDED
@@ -0,0 +1,2 @@
|
|
|
|
|
1 |
+
order deny,allow
|
2 |
+
deny from all
|
configs/test.php
DELETED
@@ -1,53 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
$_CONFIG['license_code']="";
|
3 |
-
$_CONFIG['backup_path']="/opt/lampp/htdocs/Joomla_1.6.0/";
|
4 |
-
$_CONFIG['clonerPath']="/opt/lampp/htdocs/Joomla_1.6.0/administrator/backups";
|
5 |
-
$_CONFIG['jcuser']="admin";
|
6 |
-
$_CONFIG['jcpass']='21232f297a57a5a743894a0e4a801fc3';
|
7 |
-
$_CONFIG['mysql_host']="localhost";
|
8 |
-
$_CONFIG['mysql_user']="root";
|
9 |
-
$_CONFIG['mysql_pass']='';
|
10 |
-
$_CONFIG['mysql_database']="joomla16";
|
11 |
-
$_CONFIG['select_folders']="";
|
12 |
-
$_CONFIG['select_lang']="english";
|
13 |
-
$_CONFIG['secure_ftp']="0";
|
14 |
-
$_CONFIG['backup_compress']="0";
|
15 |
-
$_CONFIG['cron_logemail']="";
|
16 |
-
$_CONFIG['cron_exclude']="";
|
17 |
-
$_CONFIG['cron_send']="0";
|
18 |
-
$_CONFIG['cron_btype']="0";
|
19 |
-
$_CONFIG['cron_bname']="";
|
20 |
-
$_CONFIG['cron_ip']="";
|
21 |
-
$_CONFIG['cron_ftp_server']="";
|
22 |
-
$_CONFIG['cron_ftp_user']="";
|
23 |
-
$_CONFIG['cron_ftp_pass']='';
|
24 |
-
$_CONFIG['cron_ftp_path']="";
|
25 |
-
$_CONFIG['cron_ftp_delb']="";
|
26 |
-
$_CONFIG['databases_incl_list']="";
|
27 |
-
$_CONFIG['cron_sql_drop']="";
|
28 |
-
$_CONFIG['cron_email_address']="";
|
29 |
-
$_CONFIG['cron_file_delete']="0";
|
30 |
-
$_CONFIG['cron_file_delete_act']="";
|
31 |
-
$_CONFIG['mem']="";
|
32 |
-
$_CONFIG['backup_refresh']="1";
|
33 |
-
$_CONFIG['refresh_time']="1";
|
34 |
-
$_CONFIG['refresh_mode']="1";
|
35 |
-
$_CONFIG['recordsPerSession']="10000";
|
36 |
-
$_CONFIG['backup_refresh_number']="100";
|
37 |
-
$_CONFIG['sql_mem']="";
|
38 |
-
$_CONFIG['enable_db_backup']="1";
|
39 |
-
$_CONFIG['zippath']="";
|
40 |
-
$_CONFIG['tarpath']="tar";
|
41 |
-
$_CONFIG['sqldump']="mysqldump --quote-names ";
|
42 |
-
$_CONFIG['system_dlink']="";
|
43 |
-
$_CONFIG['mosConfig_live_site']="localhost";
|
44 |
-
$_CONFIG['system_ftptransfer']="0";
|
45 |
-
$_CONFIG['system_mdatabases']="0";
|
46 |
-
$_CONFIG['add_backups_dir']="0";
|
47 |
-
$_CONFIG['cron_amazon_active']="";
|
48 |
-
$_CONFIG['cron_amazon_awsAccessKey']="";
|
49 |
-
$_CONFIG['cron_amazon_awsSecretKey']="";
|
50 |
-
$_CONFIG['cron_amazon_bucket']="";
|
51 |
-
$_CONFIG['cron_amazon_dirname']="";
|
52 |
-
$_CONFIG['debug']="0";
|
53 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
css/main.css
CHANGED
@@ -378,7 +378,7 @@ table.adminform th {
|
|
378 |
}
|
379 |
table.adminform td {
|
380 |
padding: 3px;
|
381 |
-
|
382 |
text-align: left;
|
383 |
}
|
384 |
table.adminform td.editor {
|
378 |
}
|
379 |
table.adminform td {
|
380 |
padding: 3px;
|
381 |
+
border: solid 0px #d5d5d5;
|
382 |
text-align: left;
|
383 |
}
|
384 |
table.adminform td.editor {
|
index.html
ADDED
File without changes
|
index.php
DELETED
@@ -1,3 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
include "admin.cloner.php";
|
3 |
-
?>
|
|
|
|
|
|
index2.php
DELETED
@@ -1,3 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
include "admin.cloner.php";
|
3 |
-
?>
|
|
|
|
|
|
install.xcloner.php
DELETED
@@ -1,25 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* @version $Id: install.xcloner.php 57 2007-07-08 18:05:52Z soeren $
|
4 |
-
* @package XCloner
|
5 |
-
* @copyright (C) 2005-2007 JoomlaPlug.com
|
6 |
-
* @license JoomalPlug.com
|
7 |
-
* @author Ovidiu
|
8 |
-
*/
|
9 |
-
function com_install(){
|
10 |
-
global $database;
|
11 |
-
|
12 |
-
if( is_callable( array( 'JFactory', 'getDBO' ))) {
|
13 |
-
$database = JFactory::getDBO();
|
14 |
-
$database->setQuery("UPDATE #__menu SET alias = 'XCloner Backup and Restore' WHERE path = 'xcloner-backup-and-restore'");
|
15 |
-
$database->query();
|
16 |
-
}
|
17 |
-
$mypath = dirname(__FILE__);
|
18 |
-
|
19 |
-
error_reporting( E_ALL ^ E_NOTICE );
|
20 |
-
|
21 |
-
//add new admin menu images
|
22 |
-
|
23 |
-
|
24 |
-
}
|
25 |
-
?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
javascript/backup.js
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
|
2 |
|
3 |
var globalUrl;
|
4 |
var step = "r1";
|
@@ -6,14 +6,14 @@ $(document).ready(function() {
|
|
6 |
var counter = 0;
|
7 |
var counter_old = 0;
|
8 |
|
9 |
-
|
10 |
|
11 |
-
|
12 |
"error":function(request, status, error) {
|
13 |
//reset state here;
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
}});
|
18 |
|
19 |
function getSize(bytes, conv){
|
@@ -32,41 +32,41 @@ $(document).ready(function() {
|
|
32 |
globalUrl = url;
|
33 |
step = "r1";
|
34 |
|
35 |
-
|
36 |
|
37 |
if(!json){
|
38 |
-
|
39 |
-
|
40 |
}
|
41 |
|
42 |
if(json.dumpsize && !json.endDump){
|
43 |
-
|
44 |
}
|
45 |
|
46 |
if(json.newDump){
|
47 |
count++;
|
48 |
-
|
49 |
if(json.databaseName!="")
|
50 |
-
|
51 |
counter = parseInt(json.startAtLine);
|
52 |
|
53 |
}else{
|
54 |
-
|
55 |
}
|
56 |
|
57 |
if(!parseInt(json.finished)){
|
58 |
//get next records
|
59 |
|
60 |
-
|
61 |
|
62 |
-
recurseUrl = "index2.php?task=recurse_database&nohtml=1&dbbackup_comp="+json.dbbackup_comp+"&dbbackup_drop="+json.dbbackup_drop+"&startAtLine="+json.startAtLine+"&startAtRecord="+json.startAtRecord+"&dumpfile="+json.dumpfile;
|
63 |
xclonerRecurseMYSQL(recurseUrl);
|
64 |
|
65 |
}
|
66 |
else{
|
67 |
|
68 |
-
|
69 |
-
var recurseUrl="index2.php?task=recurse_files&mode=start&nohtml=1";
|
70 |
xclonerRecurseJSON(recurseUrl);
|
71 |
|
72 |
}
|
@@ -77,31 +77,31 @@ $(document).ready(function() {
|
|
77 |
|
78 |
function xclonerRecurseJSON(url){
|
79 |
|
80 |
-
|
81 |
|
82 |
globalUrl = url;
|
83 |
step = "r2";
|
84 |
|
85 |
-
|
86 |
|
87 |
if(!json){
|
88 |
-
|
89 |
-
|
90 |
}
|
91 |
|
92 |
if(!parseInt(json.finished)){
|
93 |
|
94 |
-
|
95 |
|
96 |
-
var recurseUrl = "index2.php?task=recurse_files&mode="+json.mode+"&nohtml=1";
|
97 |
xclonerRecurseJSON(recurseUrl);
|
98 |
|
99 |
}
|
100 |
else{
|
101 |
var size = parseFloat(json.size)/(1024*1024);
|
102 |
-
|
103 |
-
|
104 |
-
returnUrl = "
|
105 |
xclonerGetJSON(returnUrl);
|
106 |
|
107 |
}
|
@@ -115,35 +115,35 @@ $(document).ready(function() {
|
|
115 |
globalUrl = url;
|
116 |
step = "r3";
|
117 |
|
118 |
-
|
119 |
|
120 |
if(!json){
|
121 |
-
|
122 |
-
|
123 |
}
|
124 |
|
125 |
var percent = parseInt(json.percent);
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
if(!json.finished){
|
131 |
-
var url = "
|
132 |
xclonerGetJSON(url);
|
133 |
}else{
|
134 |
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
modal: true,
|
143 |
width: 600,
|
144 |
buttons: {
|
145 |
Close: function() {
|
146 |
-
|
147 |
}
|
148 |
}
|
149 |
});
|
@@ -154,9 +154,9 @@ $(document).ready(function() {
|
|
154 |
|
155 |
}
|
156 |
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
if(step == "r1"){
|
161 |
xclonerRecurseMYSQL(globalUrl);
|
162 |
}
|
1 |
+
jQuery(document).ready(function() {
|
2 |
|
3 |
var globalUrl;
|
4 |
var step = "r1";
|
6 |
var counter = 0;
|
7 |
var counter_old = 0;
|
8 |
|
9 |
+
jQuery("#progressbar").progressbar({ value: 0 });
|
10 |
|
11 |
+
jQuery.ajaxSetup({
|
12 |
"error":function(request, status, error) {
|
13 |
//reset state here;
|
14 |
+
jQuery("#error").show();
|
15 |
+
jQuery("#errorText").append(status+" -- "+error);
|
16 |
+
jQuery("#errorText").append("<br /><br />JSON url: "+globalUrl);
|
17 |
}});
|
18 |
|
19 |
function getSize(bytes, conv){
|
32 |
globalUrl = url;
|
33 |
step = "r1";
|
34 |
|
35 |
+
jQuery.getJSON(url, function(json) {
|
36 |
|
37 |
if(!json){
|
38 |
+
jQuery("#error").show();
|
39 |
+
jQuery("#errorText").text(url);
|
40 |
}
|
41 |
|
42 |
if(json.dumpsize && !json.endDump){
|
43 |
+
jQuery("#mysqlProcess").append(" ("+getSize(json.dumpsize, 1024*1024)+" MB) <br />");
|
44 |
}
|
45 |
|
46 |
if(json.newDump){
|
47 |
count++;
|
48 |
+
//jQuery("#mysqlProcess").append(appendIcon("arrowthick-1-e"));
|
49 |
if(json.databaseName!="")
|
50 |
+
jQuery("#mysqlProcess").append("<b>["+json.databaseName+"]</b> <span id='db"+count+"'></span> tables ");
|
51 |
counter = parseInt(json.startAtLine);
|
52 |
|
53 |
}else{
|
54 |
+
jQuery("#db"+count).text(json.startAtLine - counter);
|
55 |
}
|
56 |
|
57 |
if(!parseInt(json.finished)){
|
58 |
//get next records
|
59 |
|
60 |
+
jQuery("#db"+count).text(json.startAtLine - counter);
|
61 |
|
62 |
+
recurseUrl = "../wp-content/plugins/xcloner-backup-and-restore/index2.php?task=recurse_database&nohtml=1&dbbackup_comp="+json.dbbackup_comp+"&dbbackup_drop="+json.dbbackup_drop+"&startAtLine="+json.startAtLine+"&startAtRecord="+json.startAtRecord+"&dumpfile="+json.dumpfile;
|
63 |
xclonerRecurseMYSQL(recurseUrl);
|
64 |
|
65 |
}
|
66 |
else{
|
67 |
|
68 |
+
jQuery("#fileSystem").show();
|
69 |
+
var recurseUrl="../wp-content/plugins/xcloner-backup-and-restore/index2.php?task=recurse_files&mode=start&nohtml=1";
|
70 |
xclonerRecurseJSON(recurseUrl);
|
71 |
|
72 |
}
|
77 |
|
78 |
function xclonerRecurseJSON(url){
|
79 |
|
80 |
+
jQuery("#result").hide();
|
81 |
|
82 |
globalUrl = url;
|
83 |
step = "r2";
|
84 |
|
85 |
+
jQuery.getJSON(url, function(json) {
|
86 |
|
87 |
if(!json){
|
88 |
+
jQuery("#error").show();
|
89 |
+
jQuery("#errorText").text(url);
|
90 |
}
|
91 |
|
92 |
if(!parseInt(json.finished)){
|
93 |
|
94 |
+
jQuery("#recurseStatus").text(json.tfiles);
|
95 |
|
96 |
+
var recurseUrl = "../wp-content/plugins/xcloner-backup-and-restore/index2.php?task=recurse_files&mode="+json.mode+"&nohtml=1";
|
97 |
xclonerRecurseJSON(recurseUrl);
|
98 |
|
99 |
}
|
100 |
else{
|
101 |
var size = parseFloat(json.size)/(1024*1024);
|
102 |
+
jQuery("#recurseStatus").text(" done! (Estimated size:"+size.toFixed(2)+"MB) in "+json.tfiles+" files");
|
103 |
+
jQuery("#result").show();
|
104 |
+
returnUrl = "plugins.php?page=xcloner_show&option=com_cloner&lines="+json.tfiles+"&task=refresh&backup="+backupFile+"&excl_manual=";
|
105 |
xclonerGetJSON(returnUrl);
|
106 |
|
107 |
}
|
115 |
globalUrl = url;
|
116 |
step = "r3";
|
117 |
|
118 |
+
jQuery.getJSON(url, function(json) {
|
119 |
|
120 |
if(!json){
|
121 |
+
jQuery("#error").show();
|
122 |
+
jQuery("#errorText").append(url);
|
123 |
}
|
124 |
|
125 |
var percent = parseInt(json.percent);
|
126 |
+
jQuery("#progressbar").progressbar({ value: percent });
|
127 |
+
jQuery("#backupSize").text(json.backupSize);
|
128 |
+
jQuery("#nFiles").text(json.startf);
|
129 |
+
jQuery("#percent").text(json.percent);
|
130 |
if(!json.finished){
|
131 |
+
var url = "plugins.php?page=xcloner_show&option="+json.option+"&task="+json.task+"&json="+json.json+"&startf="+json.startf+"&lines="+json.lines+"&backup="+json.backup+"&excl_manual="+json.excl_manual;
|
132 |
xclonerGetJSON(url);
|
133 |
}else{
|
134 |
|
135 |
+
jQuery("#complete").show();
|
136 |
+
jQuery("#nFiles").text(json.lines);
|
137 |
+
jQuery("#backupFiles").text(json.lines);
|
138 |
+
jQuery("#backupSizeComplete").text(json.backupSize);
|
139 |
+
jQuery("#backupName").text(json.backup);
|
140 |
+
jQuery( "#dialog:ui-dialog" ).dialog( "destroy" );
|
141 |
+
jQuery( "#dialog-message" ).dialog({
|
142 |
modal: true,
|
143 |
width: 600,
|
144 |
buttons: {
|
145 |
Close: function() {
|
146 |
+
jQuery( this ).dialog( "close" );
|
147 |
}
|
148 |
}
|
149 |
});
|
154 |
|
155 |
}
|
156 |
|
157 |
+
jQuery("#retry").click(function(){
|
158 |
+
jQuery("#error").hide();
|
159 |
+
jQuery("#errorText").empty();
|
160 |
if(step == "r1"){
|
161 |
xclonerRecurseMYSQL(globalUrl);
|
162 |
}
|
javascript/dtree.js
CHANGED
@@ -63,33 +63,33 @@ function dTree(objName) {
|
|
63 |
|
64 |
this.icon = {
|
65 |
|
66 |
-
root : 'images/logo.gif',
|
67 |
|
68 |
-
folder : 'images/folder.gif',
|
69 |
|
70 |
-
folderOpen : 'images/folderopen.gif',
|
71 |
|
72 |
-
node : 'images/page.gif',
|
73 |
|
74 |
-
empty : 'images/empty.gif',
|
75 |
|
76 |
-
line : 'images/line.gif',
|
77 |
|
78 |
-
join : 'images/join.gif',
|
79 |
|
80 |
-
joinBottom : 'images/joinbottom.gif',
|
81 |
|
82 |
-
plus : 'images/plus.gif',
|
83 |
|
84 |
-
plusBottom : 'images/plusbottom.gif',
|
85 |
|
86 |
-
minus : 'images/minus.gif',
|
87 |
|
88 |
-
minusBottom : 'images/minusbottom.gif',
|
89 |
|
90 |
-
nlPlus : 'images/nolines_plus.gif',
|
91 |
|
92 |
-
nlMinus : 'images/nolines_minus.gif'
|
93 |
|
94 |
};
|
95 |
|
63 |
|
64 |
this.icon = {
|
65 |
|
66 |
+
root : '../wp-content/plugins/xcloner-backup-and-restore/images/logo.gif',
|
67 |
|
68 |
+
folder : '../wp-content/plugins/xcloner-backup-and-restore/images/folder.gif',
|
69 |
|
70 |
+
folderOpen : '../wp-content/plugins/xcloner-backup-and-restore/images/folderopen.gif',
|
71 |
|
72 |
+
node : '../wp-content/plugins/xcloner-backup-and-restore/images/page.gif',
|
73 |
|
74 |
+
empty : '../wp-content/plugins/xcloner-backup-and-restore/images/empty.gif',
|
75 |
|
76 |
+
line : '../wp-content/plugins/xcloner-backup-and-restore/images/line.gif',
|
77 |
|
78 |
+
join : '../wp-content/plugins/xcloner-backup-and-restore/images/join.gif',
|
79 |
|
80 |
+
joinBottom : '../wp-content/plugins/xcloner-backup-and-restore/images/joinbottom.gif',
|
81 |
|
82 |
+
plus : '../wp-content/plugins/xcloner-backup-and-restore/images/plus.gif',
|
83 |
|
84 |
+
plusBottom : '../wp-content/plugins/xcloner-backup-and-restore/images/plusbottom.gif',
|
85 |
|
86 |
+
minus : '../wp-content/plugins/xcloner-backup-and-restore/images/minus.gif',
|
87 |
|
88 |
+
minusBottom : '../wp-content/plugins/xcloner-backup-and-restore/images/minusbottom.gif',
|
89 |
|
90 |
+
nlPlus : '../wp-content/plugins/xcloner-backup-and-restore/images/nolines_plus.gif',
|
91 |
|
92 |
+
nlMinus : '../wp-content/plugins/xcloner-backup-and-restore/images/nolines_minus.gif'
|
93 |
|
94 |
};
|
95 |
|
javascript/jquery-1.4.4.min.js
DELETED
@@ -1,167 +0,0 @@
|
|
1 |
-
/*!
|
2 |
-
* jQuery JavaScript Library v1.4.4
|
3 |
-
* http://jquery.com/
|
4 |
-
*
|
5 |
-
* Copyright 2010, John Resig
|
6 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
7 |
-
* http://jquery.org/license
|
8 |
-
*
|
9 |
-
* Includes Sizzle.js
|
10 |
-
* http://sizzlejs.com/
|
11 |
-
* Copyright 2010, The Dojo Foundation
|
12 |
-
* Released under the MIT, BSD, and GPL Licenses.
|
13 |
-
*
|
14 |
-
* Date: Thu Nov 11 19:04:53 2010 -0500
|
15 |
-
*/
|
16 |
-
(function(E,B){function ka(a,b,d){if(d===B&&a.nodeType===1){d=a.getAttribute("data-"+b);if(typeof d==="string"){try{d=d==="true"?true:d==="false"?false:d==="null"?null:!c.isNaN(d)?parseFloat(d):Ja.test(d)?c.parseJSON(d):d}catch(e){}c.data(a,b,d)}else d=B}return d}function U(){return false}function ca(){return true}function la(a,b,d){d[0].type=a;return c.event.handle.apply(b,d)}function Ka(a){var b,d,e,f,h,l,k,o,x,r,A,C=[];f=[];h=c.data(this,this.nodeType?"events":"__events__");if(typeof h==="function")h=
|
17 |
-
h.events;if(!(a.liveFired===this||!h||!h.live||a.button&&a.type==="click")){if(a.namespace)A=RegExp("(^|\\.)"+a.namespace.split(".").join("\\.(?:.*\\.)?")+"(\\.|$)");a.liveFired=this;var J=h.live.slice(0);for(k=0;k<J.length;k++){h=J[k];h.origType.replace(X,"")===a.type?f.push(h.selector):J.splice(k--,1)}f=c(a.target).closest(f,a.currentTarget);o=0;for(x=f.length;o<x;o++){r=f[o];for(k=0;k<J.length;k++){h=J[k];if(r.selector===h.selector&&(!A||A.test(h.namespace))){l=r.elem;e=null;if(h.preType==="mouseenter"||
|
18 |
-
h.preType==="mouseleave"){a.type=h.preType;e=c(a.relatedTarget).closest(h.selector)[0]}if(!e||e!==l)C.push({elem:l,handleObj:h,level:r.level})}}}o=0;for(x=C.length;o<x;o++){f=C[o];if(d&&f.level>d)break;a.currentTarget=f.elem;a.data=f.handleObj.data;a.handleObj=f.handleObj;A=f.handleObj.origHandler.apply(f.elem,arguments);if(A===false||a.isPropagationStopped()){d=f.level;if(A===false)b=false;if(a.isImmediatePropagationStopped())break}}return b}}function Y(a,b){return(a&&a!=="*"?a+".":"")+b.replace(La,
|
19 |
-
"`").replace(Ma,"&")}function ma(a,b,d){if(c.isFunction(b))return c.grep(a,function(f,h){return!!b.call(f,h,f)===d});else if(b.nodeType)return c.grep(a,function(f){return f===b===d});else if(typeof b==="string"){var e=c.grep(a,function(f){return f.nodeType===1});if(Na.test(b))return c.filter(b,e,!d);else b=c.filter(b,e)}return c.grep(a,function(f){return c.inArray(f,b)>=0===d})}function na(a,b){var d=0;b.each(function(){if(this.nodeName===(a[d]&&a[d].nodeName)){var e=c.data(a[d++]),f=c.data(this,
|
20 |
-
e);if(e=e&&e.events){delete f.handle;f.events={};for(var h in e)for(var l in e[h])c.event.add(this,h,e[h][l],e[h][l].data)}}})}function Oa(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function oa(a,b,d){var e=b==="width"?a.offsetWidth:a.offsetHeight;if(d==="border")return e;c.each(b==="width"?Pa:Qa,function(){d||(e-=parseFloat(c.css(a,"padding"+this))||0);if(d==="margin")e+=parseFloat(c.css(a,
|
21 |
-
"margin"+this))||0;else e-=parseFloat(c.css(a,"border"+this+"Width"))||0});return e}function da(a,b,d,e){if(c.isArray(b)&&b.length)c.each(b,function(f,h){d||Ra.test(a)?e(a,h):da(a+"["+(typeof h==="object"||c.isArray(h)?f:"")+"]",h,d,e)});else if(!d&&b!=null&&typeof b==="object")c.isEmptyObject(b)?e(a,""):c.each(b,function(f,h){da(a+"["+f+"]",h,d,e)});else e(a,b)}function S(a,b){var d={};c.each(pa.concat.apply([],pa.slice(0,b)),function(){d[this]=a});return d}function qa(a){if(!ea[a]){var b=c("<"+
|
22 |
-
a+">").appendTo("body"),d=b.css("display");b.remove();if(d==="none"||d==="")d="block";ea[a]=d}return ea[a]}function fa(a){return c.isWindow(a)?a:a.nodeType===9?a.defaultView||a.parentWindow:false}var t=E.document,c=function(){function a(){if(!b.isReady){try{t.documentElement.doScroll("left")}catch(j){setTimeout(a,1);return}b.ready()}}var b=function(j,s){return new b.fn.init(j,s)},d=E.jQuery,e=E.$,f,h=/^(?:[^<]*(<[\w\W]+>)[^>]*$|#([\w\-]+)$)/,l=/\S/,k=/^\s+/,o=/\s+$/,x=/\W/,r=/\d/,A=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,
|
23 |
-
C=/^[\],:{}\s]*$/,J=/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,w=/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,I=/(?:^|:|,)(?:\s*\[)+/g,L=/(webkit)[ \/]([\w.]+)/,g=/(opera)(?:.*version)?[ \/]([\w.]+)/,i=/(msie) ([\w.]+)/,n=/(mozilla)(?:.*? rv:([\w.]+))?/,m=navigator.userAgent,p=false,q=[],u,y=Object.prototype.toString,F=Object.prototype.hasOwnProperty,M=Array.prototype.push,N=Array.prototype.slice,O=String.prototype.trim,D=Array.prototype.indexOf,R={};b.fn=b.prototype={init:function(j,
|
24 |
-
s){var v,z,H;if(!j)return this;if(j.nodeType){this.context=this[0]=j;this.length=1;return this}if(j==="body"&&!s&&t.body){this.context=t;this[0]=t.body;this.selector="body";this.length=1;return this}if(typeof j==="string")if((v=h.exec(j))&&(v[1]||!s))if(v[1]){H=s?s.ownerDocument||s:t;if(z=A.exec(j))if(b.isPlainObject(s)){j=[t.createElement(z[1])];b.fn.attr.call(j,s,true)}else j=[H.createElement(z[1])];else{z=b.buildFragment([v[1]],[H]);j=(z.cacheable?z.fragment.cloneNode(true):z.fragment).childNodes}return b.merge(this,
|
25 |
-
j)}else{if((z=t.getElementById(v[2]))&&z.parentNode){if(z.id!==v[2])return f.find(j);this.length=1;this[0]=z}this.context=t;this.selector=j;return this}else if(!s&&!x.test(j)){this.selector=j;this.context=t;j=t.getElementsByTagName(j);return b.merge(this,j)}else return!s||s.jquery?(s||f).find(j):b(s).find(j);else if(b.isFunction(j))return f.ready(j);if(j.selector!==B){this.selector=j.selector;this.context=j.context}return b.makeArray(j,this)},selector:"",jquery:"1.4.4",length:0,size:function(){return this.length},
|
26 |
-
toArray:function(){return N.call(this,0)},get:function(j){return j==null?this.toArray():j<0?this.slice(j)[0]:this[j]},pushStack:function(j,s,v){var z=b();b.isArray(j)?M.apply(z,j):b.merge(z,j);z.prevObject=this;z.context=this.context;if(s==="find")z.selector=this.selector+(this.selector?" ":"")+v;else if(s)z.selector=this.selector+"."+s+"("+v+")";return z},each:function(j,s){return b.each(this,j,s)},ready:function(j){b.bindReady();if(b.isReady)j.call(t,b);else q&&q.push(j);return this},eq:function(j){return j===
|
27 |
-
-1?this.slice(j):this.slice(j,+j+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(N.apply(this,arguments),"slice",N.call(arguments).join(","))},map:function(j){return this.pushStack(b.map(this,function(s,v){return j.call(s,v,s)}))},end:function(){return this.prevObject||b(null)},push:M,sort:[].sort,splice:[].splice};b.fn.init.prototype=b.fn;b.extend=b.fn.extend=function(){var j,s,v,z,H,G=arguments[0]||{},K=1,Q=arguments.length,ga=false;
|
28 |
-
if(typeof G==="boolean"){ga=G;G=arguments[1]||{};K=2}if(typeof G!=="object"&&!b.isFunction(G))G={};if(Q===K){G=this;--K}for(;K<Q;K++)if((j=arguments[K])!=null)for(s in j){v=G[s];z=j[s];if(G!==z)if(ga&&z&&(b.isPlainObject(z)||(H=b.isArray(z)))){if(H){H=false;v=v&&b.isArray(v)?v:[]}else v=v&&b.isPlainObject(v)?v:{};G[s]=b.extend(ga,v,z)}else if(z!==B)G[s]=z}return G};b.extend({noConflict:function(j){E.$=e;if(j)E.jQuery=d;return b},isReady:false,readyWait:1,ready:function(j){j===true&&b.readyWait--;
|
29 |
-
if(!b.readyWait||j!==true&&!b.isReady){if(!t.body)return setTimeout(b.ready,1);b.isReady=true;if(!(j!==true&&--b.readyWait>0))if(q){var s=0,v=q;for(q=null;j=v[s++];)j.call(t,b);b.fn.trigger&&b(t).trigger("ready").unbind("ready")}}},bindReady:function(){if(!p){p=true;if(t.readyState==="complete")return setTimeout(b.ready,1);if(t.addEventListener){t.addEventListener("DOMContentLoaded",u,false);E.addEventListener("load",b.ready,false)}else if(t.attachEvent){t.attachEvent("onreadystatechange",u);E.attachEvent("onload",
|
30 |
-
b.ready);var j=false;try{j=E.frameElement==null}catch(s){}t.documentElement.doScroll&&j&&a()}}},isFunction:function(j){return b.type(j)==="function"},isArray:Array.isArray||function(j){return b.type(j)==="array"},isWindow:function(j){return j&&typeof j==="object"&&"setInterval"in j},isNaN:function(j){return j==null||!r.test(j)||isNaN(j)},type:function(j){return j==null?String(j):R[y.call(j)]||"object"},isPlainObject:function(j){if(!j||b.type(j)!=="object"||j.nodeType||b.isWindow(j))return false;if(j.constructor&&
|
31 |
-
!F.call(j,"constructor")&&!F.call(j.constructor.prototype,"isPrototypeOf"))return false;for(var s in j);return s===B||F.call(j,s)},isEmptyObject:function(j){for(var s in j)return false;return true},error:function(j){throw j;},parseJSON:function(j){if(typeof j!=="string"||!j)return null;j=b.trim(j);if(C.test(j.replace(J,"@").replace(w,"]").replace(I,"")))return E.JSON&&E.JSON.parse?E.JSON.parse(j):(new Function("return "+j))();else b.error("Invalid JSON: "+j)},noop:function(){},globalEval:function(j){if(j&&
|
32 |
-
l.test(j)){var s=t.getElementsByTagName("head")[0]||t.documentElement,v=t.createElement("script");v.type="text/javascript";if(b.support.scriptEval)v.appendChild(t.createTextNode(j));else v.text=j;s.insertBefore(v,s.firstChild);s.removeChild(v)}},nodeName:function(j,s){return j.nodeName&&j.nodeName.toUpperCase()===s.toUpperCase()},each:function(j,s,v){var z,H=0,G=j.length,K=G===B||b.isFunction(j);if(v)if(K)for(z in j){if(s.apply(j[z],v)===false)break}else for(;H<G;){if(s.apply(j[H++],v)===false)break}else if(K)for(z in j){if(s.call(j[z],
|
33 |
-
z,j[z])===false)break}else for(v=j[0];H<G&&s.call(v,H,v)!==false;v=j[++H]);return j},trim:O?function(j){return j==null?"":O.call(j)}:function(j){return j==null?"":j.toString().replace(k,"").replace(o,"")},makeArray:function(j,s){var v=s||[];if(j!=null){var z=b.type(j);j.length==null||z==="string"||z==="function"||z==="regexp"||b.isWindow(j)?M.call(v,j):b.merge(v,j)}return v},inArray:function(j,s){if(s.indexOf)return s.indexOf(j);for(var v=0,z=s.length;v<z;v++)if(s[v]===j)return v;return-1},merge:function(j,
|
34 |
-
s){var v=j.length,z=0;if(typeof s.length==="number")for(var H=s.length;z<H;z++)j[v++]=s[z];else for(;s[z]!==B;)j[v++]=s[z++];j.length=v;return j},grep:function(j,s,v){var z=[],H;v=!!v;for(var G=0,K=j.length;G<K;G++){H=!!s(j[G],G);v!==H&&z.push(j[G])}return z},map:function(j,s,v){for(var z=[],H,G=0,K=j.length;G<K;G++){H=s(j[G],G,v);if(H!=null)z[z.length]=H}return z.concat.apply([],z)},guid:1,proxy:function(j,s,v){if(arguments.length===2)if(typeof s==="string"){v=j;j=v[s];s=B}else if(s&&!b.isFunction(s)){v=
|
35 |
-
s;s=B}if(!s&&j)s=function(){return j.apply(v||this,arguments)};if(j)s.guid=j.guid=j.guid||s.guid||b.guid++;return s},access:function(j,s,v,z,H,G){var K=j.length;if(typeof s==="object"){for(var Q in s)b.access(j,Q,s[Q],z,H,v);return j}if(v!==B){z=!G&&z&&b.isFunction(v);for(Q=0;Q<K;Q++)H(j[Q],s,z?v.call(j[Q],Q,H(j[Q],s)):v,G);return j}return K?H(j[0],s):B},now:function(){return(new Date).getTime()},uaMatch:function(j){j=j.toLowerCase();j=L.exec(j)||g.exec(j)||i.exec(j)||j.indexOf("compatible")<0&&n.exec(j)||
|
36 |
-
[];return{browser:j[1]||"",version:j[2]||"0"}},browser:{}});b.each("Boolean Number String Function Array Date RegExp Object".split(" "),function(j,s){R["[object "+s+"]"]=s.toLowerCase()});m=b.uaMatch(m);if(m.browser){b.browser[m.browser]=true;b.browser.version=m.version}if(b.browser.webkit)b.browser.safari=true;if(D)b.inArray=function(j,s){return D.call(s,j)};if(!/\s/.test("\u00a0")){k=/^[\s\xA0]+/;o=/[\s\xA0]+$/}f=b(t);if(t.addEventListener)u=function(){t.removeEventListener("DOMContentLoaded",u,
|
37 |
-
false);b.ready()};else if(t.attachEvent)u=function(){if(t.readyState==="complete"){t.detachEvent("onreadystatechange",u);b.ready()}};return E.jQuery=E.$=b}();(function(){c.support={};var a=t.documentElement,b=t.createElement("script"),d=t.createElement("div"),e="script"+c.now();d.style.display="none";d.innerHTML=" <link/><table></table><a href='/a' style='color:red;float:left;opacity:.55;'>a</a><input type='checkbox'/>";var f=d.getElementsByTagName("*"),h=d.getElementsByTagName("a")[0],l=t.createElement("select"),
|
38 |
-
k=l.appendChild(t.createElement("option"));if(!(!f||!f.length||!h)){c.support={leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(h.getAttribute("style")),hrefNormalized:h.getAttribute("href")==="/a",opacity:/^0.55$/.test(h.style.opacity),cssFloat:!!h.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:k.selected,deleteExpando:true,optDisabled:false,checkClone:false,
|
39 |
-
scriptEval:false,noCloneEvent:true,boxModel:null,inlineBlockNeedsLayout:false,shrinkWrapBlocks:false,reliableHiddenOffsets:true};l.disabled=true;c.support.optDisabled=!k.disabled;b.type="text/javascript";try{b.appendChild(t.createTextNode("window."+e+"=1;"))}catch(o){}a.insertBefore(b,a.firstChild);if(E[e]){c.support.scriptEval=true;delete E[e]}try{delete b.test}catch(x){c.support.deleteExpando=false}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function r(){c.support.noCloneEvent=
|
40 |
-
false;d.detachEvent("onclick",r)});d.cloneNode(true).fireEvent("onclick")}d=t.createElement("div");d.innerHTML="<input type='radio' name='radiotest' checked='checked'/>";a=t.createDocumentFragment();a.appendChild(d.firstChild);c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var r=t.createElement("div");r.style.width=r.style.paddingLeft="1px";t.body.appendChild(r);c.boxModel=c.support.boxModel=r.offsetWidth===2;if("zoom"in r.style){r.style.display="inline";r.style.zoom=
|
41 |
-
1;c.support.inlineBlockNeedsLayout=r.offsetWidth===2;r.style.display="";r.innerHTML="<div style='width:4px;'></div>";c.support.shrinkWrapBlocks=r.offsetWidth!==2}r.innerHTML="<table><tr><td style='padding:0;display:none'></td><td>t</td></tr></table>";var A=r.getElementsByTagName("td");c.support.reliableHiddenOffsets=A[0].offsetHeight===0;A[0].style.display="";A[1].style.display="none";c.support.reliableHiddenOffsets=c.support.reliableHiddenOffsets&&A[0].offsetHeight===0;r.innerHTML="";t.body.removeChild(r).style.display=
|
42 |
-
"none"});a=function(r){var A=t.createElement("div");r="on"+r;var C=r in A;if(!C){A.setAttribute(r,"return;");C=typeof A[r]==="function"}return C};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=f=h=null}})();var ra={},Ja=/^(?:\{.*\}|\[.*\])$/;c.extend({cache:{},uuid:0,expando:"jQuery"+c.now(),noData:{embed:true,object:"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",applet:true},data:function(a,b,d){if(c.acceptData(a)){a=a==E?ra:a;var e=a.nodeType,f=e?a[c.expando]:null,h=
|
43 |
-
c.cache;if(!(e&&!f&&typeof b==="string"&&d===B)){if(e)f||(a[c.expando]=f=++c.uuid);else h=a;if(typeof b==="object")if(e)h[f]=c.extend(h[f],b);else c.extend(h,b);else if(e&&!h[f])h[f]={};a=e?h[f]:h;if(d!==B)a[b]=d;return typeof b==="string"?a[b]:a}}},removeData:function(a,b){if(c.acceptData(a)){a=a==E?ra:a;var d=a.nodeType,e=d?a[c.expando]:a,f=c.cache,h=d?f[e]:e;if(b){if(h){delete h[b];d&&c.isEmptyObject(h)&&c.removeData(a)}}else if(d&&c.support.deleteExpando)delete a[c.expando];else if(a.removeAttribute)a.removeAttribute(c.expando);
|
44 |
-
else if(d)delete f[e];else for(var l in a)delete a[l]}},acceptData:function(a){if(a.nodeName){var b=c.noData[a.nodeName.toLowerCase()];if(b)return!(b===true||a.getAttribute("classid")!==b)}return true}});c.fn.extend({data:function(a,b){var d=null;if(typeof a==="undefined"){if(this.length){var e=this[0].attributes,f;d=c.data(this[0]);for(var h=0,l=e.length;h<l;h++){f=e[h].name;if(f.indexOf("data-")===0){f=f.substr(5);ka(this[0],f,d[f])}}}return d}else if(typeof a==="object")return this.each(function(){c.data(this,
|
45 |
-
a)});var k=a.split(".");k[1]=k[1]?"."+k[1]:"";if(b===B){d=this.triggerHandler("getData"+k[1]+"!",[k[0]]);if(d===B&&this.length){d=c.data(this[0],a);d=ka(this[0],a,d)}return d===B&&k[1]?this.data(k[0]):d}else return this.each(function(){var o=c(this),x=[k[0],b];o.triggerHandler("setData"+k[1]+"!",x);c.data(this,a,b);o.triggerHandler("changeData"+k[1]+"!",x)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var e=
|
46 |
-
c.data(a,b);if(!d)return e||[];if(!e||c.isArray(d))e=c.data(a,b,c.makeArray(d));else e.push(d);return e}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),e=d.shift();if(e==="inprogress")e=d.shift();if(e){b==="fx"&&d.unshift("inprogress");e.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===B)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,
|
47 |
-
a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]||a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var sa=/[\n\t]/g,ha=/\s+/,Sa=/\r/g,Ta=/^(?:href|src|style)$/,Ua=/^(?:button|input)$/i,Va=/^(?:button|input|object|select|textarea)$/i,Wa=/^a(?:rea)?$/i,ta=/^(?:radio|checkbox)$/i;c.props={"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",
|
48 |
-
colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};c.fn.extend({attr:function(a,b){return c.access(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(x){var r=c(this);r.addClass(a.call(this,x,r.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===
|
49 |
-
1)if(f.className){for(var h=" "+f.className+" ",l=f.className,k=0,o=b.length;k<o;k++)if(h.indexOf(" "+b[k]+" ")<0)l+=" "+b[k];f.className=c.trim(l)}else f.className=a}return this},removeClass:function(a){if(c.isFunction(a))return this.each(function(o){var x=c(this);x.removeClass(a.call(this,o,x.attr("class")))});if(a&&typeof a==="string"||a===B)for(var b=(a||"").split(ha),d=0,e=this.length;d<e;d++){var f=this[d];if(f.nodeType===1&&f.className)if(a){for(var h=(" "+f.className+" ").replace(sa," "),
|
50 |
-
l=0,k=b.length;l<k;l++)h=h.replace(" "+b[l]+" "," ");f.className=c.trim(h)}else f.className=""}return this},toggleClass:function(a,b){var d=typeof a,e=typeof b==="boolean";if(c.isFunction(a))return this.each(function(f){var h=c(this);h.toggleClass(a.call(this,f,h.attr("class"),b),b)});return this.each(function(){if(d==="string")for(var f,h=0,l=c(this),k=b,o=a.split(ha);f=o[h++];){k=e?k:!l.hasClass(f);l[k?"addClass":"removeClass"](f)}else if(d==="undefined"||d==="boolean"){this.className&&c.data(this,
|
51 |
-
"__className__",this.className);this.className=this.className||a===false?"":c.data(this,"__className__")||""}})},hasClass:function(a){a=" "+a+" ";for(var b=0,d=this.length;b<d;b++)if((" "+this[b].className+" ").replace(sa," ").indexOf(a)>-1)return true;return false},val:function(a){if(!arguments.length){var b=this[0];if(b){if(c.nodeName(b,"option")){var d=b.attributes.value;return!d||d.specified?b.value:b.text}if(c.nodeName(b,"select")){var e=b.selectedIndex;d=[];var f=b.options;b=b.type==="select-one";
|
52 |
-
if(e<0)return null;var h=b?e:0;for(e=b?e+1:f.length;h<e;h++){var l=f[h];if(l.selected&&(c.support.optDisabled?!l.disabled:l.getAttribute("disabled")===null)&&(!l.parentNode.disabled||!c.nodeName(l.parentNode,"optgroup"))){a=c(l).val();if(b)return a;d.push(a)}}return d}if(ta.test(b.type)&&!c.support.checkOn)return b.getAttribute("value")===null?"on":b.value;return(b.value||"").replace(Sa,"")}return B}var k=c.isFunction(a);return this.each(function(o){var x=c(this),r=a;if(this.nodeType===1){if(k)r=
|
53 |
-
a.call(this,o,x.val());if(r==null)r="";else if(typeof r==="number")r+="";else if(c.isArray(r))r=c.map(r,function(C){return C==null?"":C+""});if(c.isArray(r)&&ta.test(this.type))this.checked=c.inArray(x.val(),r)>=0;else if(c.nodeName(this,"select")){var A=c.makeArray(r);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),A)>=0});if(!A.length)this.selectedIndex=-1}else this.value=r}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},
|
54 |
-
attr:function(a,b,d,e){if(!a||a.nodeType===3||a.nodeType===8)return B;if(e&&b in c.attrFn)return c(a)[b](d);e=a.nodeType!==1||!c.isXMLDoc(a);var f=d!==B;b=e&&c.props[b]||b;var h=Ta.test(b);if((b in a||a[b]!==B)&&e&&!h){if(f){b==="type"&&Ua.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");if(d===null)a.nodeType===1&&a.removeAttribute(b);else a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&
|
55 |
-
b.specified?b.value:Va.test(a.nodeName)||Wa.test(a.nodeName)&&a.href?0:B;return a[b]}if(!c.support.style&&e&&b==="style"){if(f)a.style.cssText=""+d;return a.style.cssText}f&&a.setAttribute(b,""+d);if(!a.attributes[b]&&a.hasAttribute&&!a.hasAttribute(b))return B;a=!c.support.hrefNormalized&&e&&h?a.getAttribute(b,2):a.getAttribute(b);return a===null?B:a}});var X=/\.(.*)$/,ia=/^(?:textarea|input|select)$/i,La=/\./g,Ma=/ /g,Xa=/[^\w\s.|`]/g,Ya=function(a){return a.replace(Xa,"\\$&")},ua={focusin:0,focusout:0};
|
56 |
-
c.event={add:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(c.isWindow(a)&&a!==E&&!a.frameElement)a=E;if(d===false)d=U;else if(!d)return;var f,h;if(d.handler){f=d;d=f.handler}if(!d.guid)d.guid=c.guid++;if(h=c.data(a)){var l=a.nodeType?"events":"__events__",k=h[l],o=h.handle;if(typeof k==="function"){o=k.handle;k=k.events}else if(!k){a.nodeType||(h[l]=h=function(){});h.events=k={}}if(!o)h.handle=o=function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(o.elem,
|
57 |
-
arguments):B};o.elem=a;b=b.split(" ");for(var x=0,r;l=b[x++];){h=f?c.extend({},f):{handler:d,data:e};if(l.indexOf(".")>-1){r=l.split(".");l=r.shift();h.namespace=r.slice(0).sort().join(".")}else{r=[];h.namespace=""}h.type=l;if(!h.guid)h.guid=d.guid;var A=k[l],C=c.event.special[l]||{};if(!A){A=k[l]=[];if(!C.setup||C.setup.call(a,e,r,o)===false)if(a.addEventListener)a.addEventListener(l,o,false);else a.attachEvent&&a.attachEvent("on"+l,o)}if(C.add){C.add.call(a,h);if(!h.handler.guid)h.handler.guid=
|
58 |
-
d.guid}A.push(h);c.event.global[l]=true}a=null}}},global:{},remove:function(a,b,d,e){if(!(a.nodeType===3||a.nodeType===8)){if(d===false)d=U;var f,h,l=0,k,o,x,r,A,C,J=a.nodeType?"events":"__events__",w=c.data(a),I=w&&w[J];if(w&&I){if(typeof I==="function"){w=I;I=I.events}if(b&&b.type){d=b.handler;b=b.type}if(!b||typeof b==="string"&&b.charAt(0)==="."){b=b||"";for(f in I)c.event.remove(a,f+b)}else{for(b=b.split(" ");f=b[l++];){r=f;k=f.indexOf(".")<0;o=[];if(!k){o=f.split(".");f=o.shift();x=RegExp("(^|\\.)"+
|
59 |
-
c.map(o.slice(0).sort(),Ya).join("\\.(?:.*\\.)?")+"(\\.|$)")}if(A=I[f])if(d){r=c.event.special[f]||{};for(h=e||0;h<A.length;h++){C=A[h];if(d.guid===C.guid){if(k||x.test(C.namespace)){e==null&&A.splice(h--,1);r.remove&&r.remove.call(a,C)}if(e!=null)break}}if(A.length===0||e!=null&&A.length===1){if(!r.teardown||r.teardown.call(a,o)===false)c.removeEvent(a,f,w.handle);delete I[f]}}else for(h=0;h<A.length;h++){C=A[h];if(k||x.test(C.namespace)){c.event.remove(a,r,C.handler,h);A.splice(h--,1)}}}if(c.isEmptyObject(I)){if(b=
|
60 |
-
w.handle)b.elem=null;delete w.events;delete w.handle;if(typeof w==="function")c.removeData(a,J);else c.isEmptyObject(w)&&c.removeData(a)}}}}},trigger:function(a,b,d,e){var f=a.type||a;if(!e){a=typeof a==="object"?a[c.expando]?a:c.extend(c.Event(f),a):c.Event(f);if(f.indexOf("!")>=0){a.type=f=f.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();c.event.global[f]&&c.each(c.cache,function(){this.events&&this.events[f]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===
|
61 |
-
8)return B;a.result=B;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(e=d.nodeType?c.data(d,"handle"):(c.data(d,"__events__")||{}).handle)&&e.apply(d,b);e=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+f]&&d["on"+f].apply(d,b)===false){a.result=false;a.preventDefault()}}catch(h){}if(!a.isPropagationStopped()&&e)c.event.trigger(a,b,e,true);else if(!a.isDefaultPrevented()){var l;e=a.target;var k=f.replace(X,""),o=c.nodeName(e,"a")&&k===
|
62 |
-
"click",x=c.event.special[k]||{};if((!x._default||x._default.call(d,a)===false)&&!o&&!(e&&e.nodeName&&c.noData[e.nodeName.toLowerCase()])){try{if(e[k]){if(l=e["on"+k])e["on"+k]=null;c.event.triggered=true;e[k]()}}catch(r){}if(l)e["on"+k]=l;c.event.triggered=false}}},handle:function(a){var b,d,e,f;d=[];var h=c.makeArray(arguments);a=h[0]=c.event.fix(a||E.event);a.currentTarget=this;b=a.type.indexOf(".")<0&&!a.exclusive;if(!b){e=a.type.split(".");a.type=e.shift();d=e.slice(0).sort();e=RegExp("(^|\\.)"+
|
63 |
-
d.join("\\.(?:.*\\.)?")+"(\\.|$)")}a.namespace=a.namespace||d.join(".");f=c.data(this,this.nodeType?"events":"__events__");if(typeof f==="function")f=f.events;d=(f||{})[a.type];if(f&&d){d=d.slice(0);f=0;for(var l=d.length;f<l;f++){var k=d[f];if(b||e.test(k.namespace)){a.handler=k.handler;a.data=k.data;a.handleObj=k;k=k.handler.apply(this,h);if(k!==B){a.result=k;if(k===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),
|
64 |
-
fix:function(a){if(a[c.expando])return a;var b=a;a=c.Event(b);for(var d=this.props.length,e;d;){e=this.props[--d];a[e]=b[e]}if(!a.target)a.target=a.srcElement||t;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=t.documentElement;d=t.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop||
|
65 |
-
d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(a.which==null&&(a.charCode!=null||a.keyCode!=null))a.which=a.charCode!=null?a.charCode:a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==B)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a){c.event.add(this,Y(a.origType,a.selector),c.extend({},a,{handler:Ka,guid:a.handler.guid}))},remove:function(a){c.event.remove(this,
|
66 |
-
Y(a.origType,a.selector),a)}},beforeunload:{setup:function(a,b,d){if(c.isWindow(this))this.onbeforeunload=d},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.removeEvent=t.removeEventListener?function(a,b,d){a.removeEventListener&&a.removeEventListener(b,d,false)}:function(a,b,d){a.detachEvent&&a.detachEvent("on"+b,d)};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=
|
67 |
-
c.now();this[c.expando]=true};c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=ca;var a=this.originalEvent;if(a)if(a.preventDefault)a.preventDefault();else a.returnValue=false},stopPropagation:function(){this.isPropagationStopped=ca;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=ca;this.stopPropagation()},isDefaultPrevented:U,isPropagationStopped:U,isImmediatePropagationStopped:U};
|
68 |
-
var va=function(a){var b=a.relatedTarget;try{for(;b&&b!==this;)b=b.parentNode;if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}}catch(d){}},wa=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?wa:va,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?wa:va)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(){if(this.nodeName.toLowerCase()!==
|
69 |
-
"form"){c.event.add(this,"click.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="submit"||d==="image")&&c(b).closest("form").length){a.liveFired=B;return la("submit",this,arguments)}});c.event.add(this,"keypress.specialSubmit",function(a){var b=a.target,d=b.type;if((d==="text"||d==="password")&&c(b).closest("form").length&&a.keyCode===13){a.liveFired=B;return la("submit",this,arguments)}})}else return false},teardown:function(){c.event.remove(this,".specialSubmit")}};if(!c.support.changeBubbles){var V,
|
70 |
-
xa=function(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(e){return e.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d},Z=function(a,b){var d=a.target,e,f;if(!(!ia.test(d.nodeName)||d.readOnly)){e=c.data(d,"_change_data");f=xa(d);if(a.type!=="focusout"||d.type!=="radio")c.data(d,"_change_data",f);if(!(e===B||f===e))if(e!=null||f){a.type="change";a.liveFired=
|
71 |
-
B;return c.event.trigger(a,b,d)}}};c.event.special.change={filters:{focusout:Z,beforedeactivate:Z,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return Z.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return Z.call(this,a)},beforeactivate:function(a){a=a.target;c.data(a,"_change_data",xa(a))}},setup:function(){if(this.type===
|
72 |
-
"file")return false;for(var a in V)c.event.add(this,a+".specialChange",V[a]);return ia.test(this.nodeName)},teardown:function(){c.event.remove(this,".specialChange");return ia.test(this.nodeName)}};V=c.event.special.change.filters;V.focus=V.beforeactivate}t.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(e){e=c.event.fix(e);e.type=b;return c.event.trigger(e,null,e.target)}c.event.special[b]={setup:function(){ua[b]++===0&&t.addEventListener(a,d,true)},teardown:function(){--ua[b]===
|
73 |
-
0&&t.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,e,f){if(typeof d==="object"){for(var h in d)this[b](h,e,d[h],f);return this}if(c.isFunction(e)||e===false){f=e;e=B}var l=b==="one"?c.proxy(f,function(o){c(this).unbind(o,l);return f.apply(this,arguments)}):f;if(d==="unload"&&b!=="one")this.one(d,e,f);else{h=0;for(var k=this.length;h<k;h++)c.event.add(this[h],d,l,e)}return this}});c.fn.extend({unbind:function(a,b){if(typeof a==="object"&&!a.preventDefault)for(var d in a)this.unbind(d,
|
74 |
-
a[d]);else{d=0;for(var e=this.length;d<e;d++)c.event.remove(this[d],a,b)}return this},delegate:function(a,b,d,e){return this.live(b,d,e,a)},undelegate:function(a,b,d){return arguments.length===0?this.unbind("live"):this.die(b,null,d,a)},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){var d=c.Event(a);d.preventDefault();d.stopPropagation();c.event.trigger(d,b,this[0]);return d.result}},toggle:function(a){for(var b=arguments,d=
|
75 |
-
1;d<b.length;)c.proxy(a,b[d++]);return this.click(c.proxy(a,function(e){var f=(c.data(this,"lastToggle"+a.guid)||0)%d;c.data(this,"lastToggle"+a.guid,f+1);e.preventDefault();return b[f].apply(this,arguments)||false}))},hover:function(a,b){return this.mouseenter(a).mouseleave(b||a)}});var ya={focus:"focusin",blur:"focusout",mouseenter:"mouseover",mouseleave:"mouseout"};c.each(["live","die"],function(a,b){c.fn[b]=function(d,e,f,h){var l,k=0,o,x,r=h||this.selector;h=h?this:c(this.context);if(typeof d===
|
76 |
-
"object"&&!d.preventDefault){for(l in d)h[b](l,e,d[l],r);return this}if(c.isFunction(e)){f=e;e=B}for(d=(d||"").split(" ");(l=d[k++])!=null;){o=X.exec(l);x="";if(o){x=o[0];l=l.replace(X,"")}if(l==="hover")d.push("mouseenter"+x,"mouseleave"+x);else{o=l;if(l==="focus"||l==="blur"){d.push(ya[l]+x);l+=x}else l=(ya[l]||l)+x;if(b==="live"){x=0;for(var A=h.length;x<A;x++)c.event.add(h[x],"live."+Y(l,r),{data:e,selector:r,handler:f,origType:l,origHandler:f,preType:o})}else h.unbind("live."+Y(l,r),f)}}return this}});
|
77 |
-
c.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error".split(" "),function(a,b){c.fn[b]=function(d,e){if(e==null){e=d;d=null}return arguments.length>0?this.bind(b,d,e):this.trigger(b)};if(c.attrFn)c.attrFn[b]=true});E.attachEvent&&!E.addEventListener&&c(E).bind("unload",function(){for(var a in c.cache)if(c.cache[a].handle)try{c.event.remove(c.cache[a].handle.elem)}catch(b){}});
|
78 |
-
(function(){function a(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1&&!q){y.sizcache=n;y.sizset=p}if(y.nodeName.toLowerCase()===i){F=y;break}y=y[g]}m[p]=F}}}function b(g,i,n,m,p,q){p=0;for(var u=m.length;p<u;p++){var y=m[p];if(y){var F=false;for(y=y[g];y;){if(y.sizcache===n){F=m[y.sizset];break}if(y.nodeType===1){if(!q){y.sizcache=n;y.sizset=p}if(typeof i!=="string"){if(y===i){F=true;break}}else if(k.filter(i,
|
79 |
-
[y]).length>0){F=y;break}}y=y[g]}m[p]=F}}}var d=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^\[\]]*\]|['"][^'"]*['"]|[^\[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,f=Object.prototype.toString,h=false,l=true;[0,0].sort(function(){l=false;return 0});var k=function(g,i,n,m){n=n||[];var p=i=i||t;if(i.nodeType!==1&&i.nodeType!==9)return[];if(!g||typeof g!=="string")return n;var q,u,y,F,M,N=true,O=k.isXML(i),D=[],R=g;do{d.exec("");if(q=d.exec(R)){R=q[3];D.push(q[1]);if(q[2]){F=q[3];
|
80 |
-
break}}}while(q);if(D.length>1&&x.exec(g))if(D.length===2&&o.relative[D[0]])u=L(D[0]+D[1],i);else for(u=o.relative[D[0]]?[i]:k(D.shift(),i);D.length;){g=D.shift();if(o.relative[g])g+=D.shift();u=L(g,u)}else{if(!m&&D.length>1&&i.nodeType===9&&!O&&o.match.ID.test(D[0])&&!o.match.ID.test(D[D.length-1])){q=k.find(D.shift(),i,O);i=q.expr?k.filter(q.expr,q.set)[0]:q.set[0]}if(i){q=m?{expr:D.pop(),set:C(m)}:k.find(D.pop(),D.length===1&&(D[0]==="~"||D[0]==="+")&&i.parentNode?i.parentNode:i,O);u=q.expr?k.filter(q.expr,
|
81 |
-
q.set):q.set;if(D.length>0)y=C(u);else N=false;for(;D.length;){q=M=D.pop();if(o.relative[M])q=D.pop();else M="";if(q==null)q=i;o.relative[M](y,q,O)}}else y=[]}y||(y=u);y||k.error(M||g);if(f.call(y)==="[object Array]")if(N)if(i&&i.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&k.contains(i,y[g])))n.push(u[g])}else for(g=0;y[g]!=null;g++)y[g]&&y[g].nodeType===1&&n.push(u[g]);else n.push.apply(n,y);else C(y,n);if(F){k(F,p,n,m);k.uniqueSort(n)}return n};k.uniqueSort=function(g){if(w){h=
|
82 |
-
l;g.sort(w);if(h)for(var i=1;i<g.length;i++)g[i]===g[i-1]&&g.splice(i--,1)}return g};k.matches=function(g,i){return k(g,null,null,i)};k.matchesSelector=function(g,i){return k(i,null,null,[g]).length>0};k.find=function(g,i,n){var m;if(!g)return[];for(var p=0,q=o.order.length;p<q;p++){var u,y=o.order[p];if(u=o.leftMatch[y].exec(g)){var F=u[1];u.splice(1,1);if(F.substr(F.length-1)!=="\\"){u[1]=(u[1]||"").replace(/\\/g,"");m=o.find[y](u,i,n);if(m!=null){g=g.replace(o.match[y],"");break}}}}m||(m=i.getElementsByTagName("*"));
|
83 |
-
return{set:m,expr:g}};k.filter=function(g,i,n,m){for(var p,q,u=g,y=[],F=i,M=i&&i[0]&&k.isXML(i[0]);g&&i.length;){for(var N in o.filter)if((p=o.leftMatch[N].exec(g))!=null&&p[2]){var O,D,R=o.filter[N];D=p[1];q=false;p.splice(1,1);if(D.substr(D.length-1)!=="\\"){if(F===y)y=[];if(o.preFilter[N])if(p=o.preFilter[N](p,F,n,y,m,M)){if(p===true)continue}else q=O=true;if(p)for(var j=0;(D=F[j])!=null;j++)if(D){O=R(D,p,j,F);var s=m^!!O;if(n&&O!=null)if(s)q=true;else F[j]=false;else if(s){y.push(D);q=true}}if(O!==
|
84 |
-
B){n||(F=y);g=g.replace(o.match[N],"");if(!q)return[];break}}}if(g===u)if(q==null)k.error(g);else break;u=g}return F};k.error=function(g){throw"Syntax error, unrecognized expression: "+g;};var o=k.selectors={order:["ID","NAME","TAG"],match:{ID:/#((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,CLASS:/\.((?:[\w\u00c0-\uFFFF\-]|\\.)+)/,NAME:/\[name=['"]*((?:[\w\u00c0-\uFFFF\-]|\\.)+)['"]*\]/,ATTR:/\[\s*((?:[\w\u00c0-\uFFFF\-]|\\.)+)\s*(?:(\S?=)\s*(['"]*)(.*?)\3|)\s*\]/,TAG:/^((?:[\w\u00c0-\uFFFF\*\-]|\\.)+)/,CHILD:/:(only|nth|last|first)-child(?:\((even|odd|[\dn+\-]*)\))?/,
|
85 |
-
POS:/:(nth|eq|gt|lt|first|last|even|odd)(?:\((\d*)\))?(?=[^\-]|$)/,PSEUDO:/:((?:[\w\u00c0-\uFFFF\-]|\\.)+)(?:\((['"]?)((?:\([^\)]+\)|[^\(\)]*)+)\2\))?/},leftMatch:{},attrMap:{"class":"className","for":"htmlFor"},attrHandle:{href:function(g){return g.getAttribute("href")}},relative:{"+":function(g,i){var n=typeof i==="string",m=n&&!/\W/.test(i);n=n&&!m;if(m)i=i.toLowerCase();m=0;for(var p=g.length,q;m<p;m++)if(q=g[m]){for(;(q=q.previousSibling)&&q.nodeType!==1;);g[m]=n||q&&q.nodeName.toLowerCase()===
|
86 |
-
i?q||false:q===i}n&&k.filter(i,g,true)},">":function(g,i){var n,m=typeof i==="string",p=0,q=g.length;if(m&&!/\W/.test(i))for(i=i.toLowerCase();p<q;p++){if(n=g[p]){n=n.parentNode;g[p]=n.nodeName.toLowerCase()===i?n:false}}else{for(;p<q;p++)if(n=g[p])g[p]=m?n.parentNode:n.parentNode===i;m&&k.filter(i,g,true)}},"":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=i=i.toLowerCase();q=a}q("parentNode",i,p,g,m,n)},"~":function(g,i,n){var m,p=e++,q=b;if(typeof i==="string"&&!/\W/.test(i)){m=
|
87 |
-
i=i.toLowerCase();q=a}q("previousSibling",i,p,g,m,n)}},find:{ID:function(g,i,n){if(typeof i.getElementById!=="undefined"&&!n)return(g=i.getElementById(g[1]))&&g.parentNode?[g]:[]},NAME:function(g,i){if(typeof i.getElementsByName!=="undefined"){for(var n=[],m=i.getElementsByName(g[1]),p=0,q=m.length;p<q;p++)m[p].getAttribute("name")===g[1]&&n.push(m[p]);return n.length===0?null:n}},TAG:function(g,i){return i.getElementsByTagName(g[1])}},preFilter:{CLASS:function(g,i,n,m,p,q){g=" "+g[1].replace(/\\/g,
|
88 |
-
"")+" ";if(q)return g;q=0;for(var u;(u=i[q])!=null;q++)if(u)if(p^(u.className&&(" "+u.className+" ").replace(/[\t\n]/g," ").indexOf(g)>=0))n||m.push(u);else if(n)i[q]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var i=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&&"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=i[1]+(i[2]||1)-0;g[3]=i[3]-0}g[0]=e++;return g},ATTR:function(g,i,n,
|
89 |
-
m,p,q){i=g[1].replace(/\\/g,"");if(!q&&o.attrMap[i])g[1]=o.attrMap[i];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,i,n,m,p){if(g[1]==="not")if((d.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=k(g[3],null,null,i);else{g=k.filter(g[3],i,n,true^p);n||m.push.apply(m,g);return false}else if(o.match.POS.test(g[0])||o.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true);return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===
|
90 |
-
true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,i,n){return!!k(n[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"===g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===
|
91 |
-
g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,i){return i===0},last:function(g,i,n,m){return i===m.length-1},even:function(g,i){return i%2===0},odd:function(g,i){return i%2===1},lt:function(g,i,n){return i<n[3]-0},gt:function(g,i,n){return i>n[3]-0},nth:function(g,i,n){return n[3]-
|
92 |
-
0===i},eq:function(g,i,n){return n[3]-0===i}},filter:{PSEUDO:function(g,i,n,m){var p=i[1],q=o.filters[p];if(q)return q(g,n,i,m);else if(p==="contains")return(g.textContent||g.innerText||k.getText([g])||"").indexOf(i[3])>=0;else if(p==="not"){i=i[3];n=0;for(m=i.length;n<m;n++)if(i[n]===g)return false;return true}else k.error("Syntax error, unrecognized expression: "+p)},CHILD:function(g,i){var n=i[1],m=g;switch(n){case "only":case "first":for(;m=m.previousSibling;)if(m.nodeType===1)return false;if(n===
|
93 |
-
"first")return true;m=g;case "last":for(;m=m.nextSibling;)if(m.nodeType===1)return false;return true;case "nth":n=i[2];var p=i[3];if(n===1&&p===0)return true;var q=i[0],u=g.parentNode;if(u&&(u.sizcache!==q||!g.nodeIndex)){var y=0;for(m=u.firstChild;m;m=m.nextSibling)if(m.nodeType===1)m.nodeIndex=++y;u.sizcache=q}m=g.nodeIndex-p;return n===0?m===0:m%n===0&&m/n>=0}},ID:function(g,i){return g.nodeType===1&&g.getAttribute("id")===i},TAG:function(g,i){return i==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===
|
94 |
-
i},CLASS:function(g,i){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(i)>-1},ATTR:function(g,i){var n=i[1];n=o.attrHandle[n]?o.attrHandle[n](g):g[n]!=null?g[n]:g.getAttribute(n);var m=n+"",p=i[2],q=i[4];return n==null?p==="!=":p==="="?m===q:p==="*="?m.indexOf(q)>=0:p==="~="?(" "+m+" ").indexOf(q)>=0:!q?m&&n!==false:p==="!="?m!==q:p==="^="?m.indexOf(q)===0:p==="$="?m.substr(m.length-q.length)===q:p==="|="?m===q||m.substr(0,q.length+1)===q+"-":false},POS:function(g,i,n,m){var p=o.setFilters[i[2]];
|
95 |
-
if(p)return p(g,n,i,m)}}},x=o.match.POS,r=function(g,i){return"\\"+(i-0+1)},A;for(A in o.match){o.match[A]=RegExp(o.match[A].source+/(?![^\[]*\])(?![^\(]*\))/.source);o.leftMatch[A]=RegExp(/(^(?:.|\r|\n)*?)/.source+o.match[A].source.replace(/\\(\d+)/g,r))}var C=function(g,i){g=Array.prototype.slice.call(g,0);if(i){i.push.apply(i,g);return i}return g};try{Array.prototype.slice.call(t.documentElement.childNodes,0)}catch(J){C=function(g,i){var n=0,m=i||[];if(f.call(g)==="[object Array]")Array.prototype.push.apply(m,
|
96 |
-
g);else if(typeof g.length==="number")for(var p=g.length;n<p;n++)m.push(g[n]);else for(;g[n];n++)m.push(g[n]);return m}}var w,I;if(t.documentElement.compareDocumentPosition)w=function(g,i){if(g===i){h=true;return 0}if(!g.compareDocumentPosition||!i.compareDocumentPosition)return g.compareDocumentPosition?-1:1;return g.compareDocumentPosition(i)&4?-1:1};else{w=function(g,i){var n,m,p=[],q=[];n=g.parentNode;m=i.parentNode;var u=n;if(g===i){h=true;return 0}else if(n===m)return I(g,i);else if(n){if(!m)return 1}else return-1;
|
97 |
-
for(;u;){p.unshift(u);u=u.parentNode}for(u=m;u;){q.unshift(u);u=u.parentNode}n=p.length;m=q.length;for(u=0;u<n&&u<m;u++)if(p[u]!==q[u])return I(p[u],q[u]);return u===n?I(g,q[u],-1):I(p[u],i,1)};I=function(g,i,n){if(g===i)return n;for(g=g.nextSibling;g;){if(g===i)return-1;g=g.nextSibling}return 1}}k.getText=function(g){for(var i="",n,m=0;g[m];m++){n=g[m];if(n.nodeType===3||n.nodeType===4)i+=n.nodeValue;else if(n.nodeType!==8)i+=k.getText(n.childNodes)}return i};(function(){var g=t.createElement("div"),
|
98 |
-
i="script"+(new Date).getTime(),n=t.documentElement;g.innerHTML="<a name='"+i+"'/>";n.insertBefore(g,n.firstChild);if(t.getElementById(i)){o.find.ID=function(m,p,q){if(typeof p.getElementById!=="undefined"&&!q)return(p=p.getElementById(m[1]))?p.id===m[1]||typeof p.getAttributeNode!=="undefined"&&p.getAttributeNode("id").nodeValue===m[1]?[p]:B:[]};o.filter.ID=function(m,p){var q=typeof m.getAttributeNode!=="undefined"&&m.getAttributeNode("id");return m.nodeType===1&&q&&q.nodeValue===p}}n.removeChild(g);
|
99 |
-
n=g=null})();(function(){var g=t.createElement("div");g.appendChild(t.createComment(""));if(g.getElementsByTagName("*").length>0)o.find.TAG=function(i,n){var m=n.getElementsByTagName(i[1]);if(i[1]==="*"){for(var p=[],q=0;m[q];q++)m[q].nodeType===1&&p.push(m[q]);m=p}return m};g.innerHTML="<a href='#'></a>";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")o.attrHandle.href=function(i){return i.getAttribute("href",2)};g=null})();t.querySelectorAll&&
|
100 |
-
function(){var g=k,i=t.createElement("div");i.innerHTML="<p class='TEST'></p>";if(!(i.querySelectorAll&&i.querySelectorAll(".TEST").length===0)){k=function(m,p,q,u){p=p||t;m=m.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!u&&!k.isXML(p))if(p.nodeType===9)try{return C(p.querySelectorAll(m),q)}catch(y){}else if(p.nodeType===1&&p.nodeName.toLowerCase()!=="object"){var F=p.getAttribute("id"),M=F||"__sizzle__";F||p.setAttribute("id",M);try{return C(p.querySelectorAll("#"+M+" "+m),q)}catch(N){}finally{F||
|
101 |
-
p.removeAttribute("id")}}return g(m,p,q,u)};for(var n in g)k[n]=g[n];i=null}}();(function(){var g=t.documentElement,i=g.matchesSelector||g.mozMatchesSelector||g.webkitMatchesSelector||g.msMatchesSelector,n=false;try{i.call(t.documentElement,"[test!='']:sizzle")}catch(m){n=true}if(i)k.matchesSelector=function(p,q){q=q.replace(/\=\s*([^'"\]]*)\s*\]/g,"='$1']");if(!k.isXML(p))try{if(n||!o.match.PSEUDO.test(q)&&!/!=/.test(q))return i.call(p,q)}catch(u){}return k(q,null,null,[p]).length>0}})();(function(){var g=
|
102 |
-
t.createElement("div");g.innerHTML="<div class='test e'></div><div class='test'></div>";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length===0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){o.order.splice(1,0,"CLASS");o.find.CLASS=function(i,n,m){if(typeof n.getElementsByClassName!=="undefined"&&!m)return n.getElementsByClassName(i[1])};g=null}}})();k.contains=t.documentElement.contains?function(g,i){return g!==i&&(g.contains?g.contains(i):true)}:t.documentElement.compareDocumentPosition?
|
103 |
-
function(g,i){return!!(g.compareDocumentPosition(i)&16)}:function(){return false};k.isXML=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false};var L=function(g,i){for(var n,m=[],p="",q=i.nodeType?[i]:i;n=o.match.PSEUDO.exec(g);){p+=n[0];g=g.replace(o.match.PSEUDO,"")}g=o.relative[g]?g+"*":g;n=0;for(var u=q.length;n<u;n++)k(g,q[n],m);return k.filter(p,m)};c.find=k;c.expr=k.selectors;c.expr[":"]=c.expr.filters;c.unique=k.uniqueSort;c.text=k.getText;c.isXMLDoc=k.isXML;
|
104 |
-
c.contains=k.contains})();var Za=/Until$/,$a=/^(?:parents|prevUntil|prevAll)/,ab=/,/,Na=/^.[^:#\[\.,]*$/,bb=Array.prototype.slice,cb=c.expr.match.POS;c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,e=0,f=this.length;e<f;e++){d=b.length;c.find(a,this[e],b);if(e>0)for(var h=d;h<b.length;h++)for(var l=0;l<d;l++)if(b[l]===b[h]){b.splice(h--,1);break}}return b},has:function(a){var b=c(a);return this.filter(function(){for(var d=0,e=b.length;d<e;d++)if(c.contains(this,b[d]))return true})},
|
105 |
-
not:function(a){return this.pushStack(ma(this,a,false),"not",a)},filter:function(a){return this.pushStack(ma(this,a,true),"filter",a)},is:function(a){return!!a&&c.filter(a,this).length>0},closest:function(a,b){var d=[],e,f,h=this[0];if(c.isArray(a)){var l,k={},o=1;if(h&&a.length){e=0;for(f=a.length;e<f;e++){l=a[e];k[l]||(k[l]=c.expr.match.POS.test(l)?c(l,b||this.context):l)}for(;h&&h.ownerDocument&&h!==b;){for(l in k){e=k[l];if(e.jquery?e.index(h)>-1:c(h).is(e))d.push({selector:l,elem:h,level:o})}h=
|
106 |
-
h.parentNode;o++}}return d}l=cb.test(a)?c(a,b||this.context):null;e=0;for(f=this.length;e<f;e++)for(h=this[e];h;)if(l?l.index(h)>-1:c.find.matchesSelector(h,a)){d.push(h);break}else{h=h.parentNode;if(!h||!h.ownerDocument||h===b)break}d=d.length>1?c.unique(d):d;return this.pushStack(d,"closest",a)},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){var d=typeof a==="string"?c(a,b||this.context):
|
107 |
-
c.makeArray(a),e=c.merge(this.get(),d);return this.pushStack(!d[0]||!d[0].parentNode||d[0].parentNode.nodeType===11||!e[0]||!e[0].parentNode||e[0].parentNode.nodeType===11?e:c.unique(e))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,
|
108 |
-
2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")},nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,
|
109 |
-
b){c.fn[a]=function(d,e){var f=c.map(this,b,d);Za.test(a)||(e=d);if(e&&typeof e==="string")f=c.filter(e,f);f=this.length>1?c.unique(f):f;if((this.length>1||ab.test(e))&&$a.test(a))f=f.reverse();return this.pushStack(f,a,bb.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return b.length===1?c.find.matchesSelector(b[0],a)?[b[0]]:[]:c.find.matches(a,b)},dir:function(a,b,d){var e=[];for(a=a[b];a&&a.nodeType!==9&&(d===B||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&
|
110 |
-
e.push(a);a=a[b]}return e},nth:function(a,b,d){b=b||1;for(var e=0;a;a=a[d])if(a.nodeType===1&&++e===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!==b&&d.push(a);return d}});var za=/ jQuery\d+="(?:\d+|null)"/g,$=/^\s+/,Aa=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig,Ba=/<([\w:]+)/,db=/<tbody/i,eb=/<|&#?\w+;/,Ca=/<(?:script|object|embed|option|style)/i,Da=/checked\s*(?:[^=]|=\s*.checked.)/i,fb=/\=([^="'>\s]+\/)>/g,P={option:[1,
|
111 |
-
"<select multiple='multiple'>","</select>"],legend:[1,"<fieldset>","</fieldset>"],thead:[1,"<table>","</table>"],tr:[2,"<table><tbody>","</tbody></table>"],td:[3,"<table><tbody><tr>","</tr></tbody></table>"],col:[2,"<table><tbody></tbody><colgroup>","</colgroup></table>"],area:[1,"<map>","</map>"],_default:[0,"",""]};P.optgroup=P.option;P.tbody=P.tfoot=P.colgroup=P.caption=P.thead;P.th=P.td;if(!c.support.htmlSerialize)P._default=[1,"div<div>","</div>"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=
|
112 |
-
c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==B)return this.empty().append((this[0]&&this[0].ownerDocument||t).createTextNode(a));return c.text(this)},wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},
|
113 |
-
wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length?d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},
|
114 |
-
prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,
|
115 |
-
this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},remove:function(a,b){for(var d=0,e;(e=this[d])!=null;d++)if(!a||c.filter(a,[e]).length){if(!b&&e.nodeType===1){c.cleanData(e.getElementsByTagName("*"));c.cleanData([e])}e.parentNode&&e.parentNode.removeChild(e)}return this},empty:function(){for(var a=0,b;(b=this[a])!=null;a++)for(b.nodeType===1&&c.cleanData(b.getElementsByTagName("*"));b.firstChild;)b.removeChild(b.firstChild);
|
116 |
-
return this},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&&!c.isXMLDoc(this)){var d=this.outerHTML,e=this.ownerDocument;if(!d){d=e.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(za,"").replace(fb,'="$1">').replace($,"")],e)[0]}else return this.cloneNode(true)});if(a===true){na(this,b);na(this.find("*"),b.find("*"))}return b},html:function(a){if(a===B)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(za,""):null;
|
117 |
-
else if(typeof a==="string"&&!Ca.test(a)&&(c.support.leadingWhitespace||!$.test(a))&&!P[(Ba.exec(a)||["",""])[1].toLowerCase()]){a=a.replace(Aa,"<$1></$2>");try{for(var b=0,d=this.length;b<d;b++)if(this[b].nodeType===1){c.cleanData(this[b].getElementsByTagName("*"));this[b].innerHTML=a}}catch(e){this.empty().append(a)}}else c.isFunction(a)?this.each(function(f){var h=c(this);h.html(a.call(this,f,h.html()))}):this.empty().append(a);return this},replaceWith:function(a){if(this[0]&&this[0].parentNode){if(c.isFunction(a))return this.each(function(b){var d=
|
118 |
-
c(this),e=d.html();d.replaceWith(a.call(this,b,e))});if(typeof a!=="string")a=c(a).detach();return this.each(function(){var b=this.nextSibling,d=this.parentNode;c(this).remove();b?c(b).before(a):c(d).append(a)})}else return this.pushStack(c(c.isFunction(a)?a():a),"replaceWith",a)},detach:function(a){return this.remove(a,true)},domManip:function(a,b,d){var e,f,h,l=a[0],k=[];if(!c.support.checkClone&&arguments.length===3&&typeof l==="string"&&Da.test(l))return this.each(function(){c(this).domManip(a,
|
119 |
-
b,d,true)});if(c.isFunction(l))return this.each(function(x){var r=c(this);a[0]=l.call(this,x,b?r.html():B);r.domManip(a,b,d)});if(this[0]){e=l&&l.parentNode;e=c.support.parentNode&&e&&e.nodeType===11&&e.childNodes.length===this.length?{fragment:e}:c.buildFragment(a,this,k);h=e.fragment;if(f=h.childNodes.length===1?h=h.firstChild:h.firstChild){b=b&&c.nodeName(f,"tr");f=0;for(var o=this.length;f<o;f++)d.call(b?c.nodeName(this[f],"table")?this[f].getElementsByTagName("tbody")[0]||this[f].appendChild(this[f].ownerDocument.createElement("tbody")):
|
120 |
-
this[f]:this[f],f>0||e.cacheable||this.length>1?h.cloneNode(true):h)}k.length&&c.each(k,Oa)}return this}});c.buildFragment=function(a,b,d){var e,f,h;b=b&&b[0]?b[0].ownerDocument||b[0]:t;if(a.length===1&&typeof a[0]==="string"&&a[0].length<512&&b===t&&!Ca.test(a[0])&&(c.support.checkClone||!Da.test(a[0]))){f=true;if(h=c.fragments[a[0]])if(h!==1)e=h}if(!e){e=b.createDocumentFragment();c.clean(a,b,e,d)}if(f)c.fragments[a[0]]=h?e:1;return{fragment:e,cacheable:f}};c.fragments={};c.each({appendTo:"append",
|
121 |
-
prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(a,b){c.fn[a]=function(d){var e=[];d=c(d);var f=this.length===1&&this[0].parentNode;if(f&&f.nodeType===11&&f.childNodes.length===1&&d.length===1){d[b](this[0]);return this}else{f=0;for(var h=d.length;f<h;f++){var l=(f>0?this.clone(true):this).get();c(d[f])[b](l);e=e.concat(l)}return this.pushStack(e,a,d.selector)}}});c.extend({clean:function(a,b,d,e){b=b||t;if(typeof b.createElement==="undefined")b=b.ownerDocument||
|
122 |
-
b[0]&&b[0].ownerDocument||t;for(var f=[],h=0,l;(l=a[h])!=null;h++){if(typeof l==="number")l+="";if(l){if(typeof l==="string"&&!eb.test(l))l=b.createTextNode(l);else if(typeof l==="string"){l=l.replace(Aa,"<$1></$2>");var k=(Ba.exec(l)||["",""])[1].toLowerCase(),o=P[k]||P._default,x=o[0],r=b.createElement("div");for(r.innerHTML=o[1]+l+o[2];x--;)r=r.lastChild;if(!c.support.tbody){x=db.test(l);k=k==="table"&&!x?r.firstChild&&r.firstChild.childNodes:o[1]==="<table>"&&!x?r.childNodes:[];for(o=k.length-
|
123 |
-
1;o>=0;--o)c.nodeName(k[o],"tbody")&&!k[o].childNodes.length&&k[o].parentNode.removeChild(k[o])}!c.support.leadingWhitespace&&$.test(l)&&r.insertBefore(b.createTextNode($.exec(l)[0]),r.firstChild);l=r.childNodes}if(l.nodeType)f.push(l);else f=c.merge(f,l)}}if(d)for(h=0;f[h];h++)if(e&&c.nodeName(f[h],"script")&&(!f[h].type||f[h].type.toLowerCase()==="text/javascript"))e.push(f[h].parentNode?f[h].parentNode.removeChild(f[h]):f[h]);else{f[h].nodeType===1&&f.splice.apply(f,[h+1,0].concat(c.makeArray(f[h].getElementsByTagName("script"))));
|
124 |
-
d.appendChild(f[h])}return f},cleanData:function(a){for(var b,d,e=c.cache,f=c.event.special,h=c.support.deleteExpando,l=0,k;(k=a[l])!=null;l++)if(!(k.nodeName&&c.noData[k.nodeName.toLowerCase()]))if(d=k[c.expando]){if((b=e[d])&&b.events)for(var o in b.events)f[o]?c.event.remove(k,o):c.removeEvent(k,o,b.handle);if(h)delete k[c.expando];else k.removeAttribute&&k.removeAttribute(c.expando);delete e[d]}}});var Ea=/alpha\([^)]*\)/i,gb=/opacity=([^)]*)/,hb=/-([a-z])/ig,ib=/([A-Z])/g,Fa=/^-?\d+(?:px)?$/i,
|
125 |
-
jb=/^-?\d/,kb={position:"absolute",visibility:"hidden",display:"block"},Pa=["Left","Right"],Qa=["Top","Bottom"],W,Ga,aa,lb=function(a,b){return b.toUpperCase()};c.fn.css=function(a,b){if(arguments.length===2&&b===B)return this;return c.access(this,a,b,true,function(d,e,f){return f!==B?c.style(d,e,f):c.css(d,e)})};c.extend({cssHooks:{opacity:{get:function(a,b){if(b){var d=W(a,"opacity","opacity");return d===""?"1":d}else return a.style.opacity}}},cssNumber:{zIndex:true,fontWeight:true,opacity:true,
|
126 |
-
zoom:true,lineHeight:true},cssProps:{"float":c.support.cssFloat?"cssFloat":"styleFloat"},style:function(a,b,d,e){if(!(!a||a.nodeType===3||a.nodeType===8||!a.style)){var f,h=c.camelCase(b),l=a.style,k=c.cssHooks[h];b=c.cssProps[h]||h;if(d!==B){if(!(typeof d==="number"&&isNaN(d)||d==null)){if(typeof d==="number"&&!c.cssNumber[h])d+="px";if(!k||!("set"in k)||(d=k.set(a,d))!==B)try{l[b]=d}catch(o){}}}else{if(k&&"get"in k&&(f=k.get(a,false,e))!==B)return f;return l[b]}}},css:function(a,b,d){var e,f=c.camelCase(b),
|
127 |
-
h=c.cssHooks[f];b=c.cssProps[f]||f;if(h&&"get"in h&&(e=h.get(a,true,d))!==B)return e;else if(W)return W(a,b,f)},swap:function(a,b,d){var e={},f;for(f in b){e[f]=a.style[f];a.style[f]=b[f]}d.call(a);for(f in b)a.style[f]=e[f]},camelCase:function(a){return a.replace(hb,lb)}});c.curCSS=c.css;c.each(["height","width"],function(a,b){c.cssHooks[b]={get:function(d,e,f){var h;if(e){if(d.offsetWidth!==0)h=oa(d,b,f);else c.swap(d,kb,function(){h=oa(d,b,f)});if(h<=0){h=W(d,b,b);if(h==="0px"&&aa)h=aa(d,b,b);
|
128 |
-
if(h!=null)return h===""||h==="auto"?"0px":h}if(h<0||h==null){h=d.style[b];return h===""||h==="auto"?"0px":h}return typeof h==="string"?h:h+"px"}},set:function(d,e){if(Fa.test(e)){e=parseFloat(e);if(e>=0)return e+"px"}else return e}}});if(!c.support.opacity)c.cssHooks.opacity={get:function(a,b){return gb.test((b&&a.currentStyle?a.currentStyle.filter:a.style.filter)||"")?parseFloat(RegExp.$1)/100+"":b?"1":""},set:function(a,b){var d=a.style;d.zoom=1;var e=c.isNaN(b)?"":"alpha(opacity="+b*100+")",f=
|
129 |
-
d.filter||"";d.filter=Ea.test(f)?f.replace(Ea,e):d.filter+" "+e}};if(t.defaultView&&t.defaultView.getComputedStyle)Ga=function(a,b,d){var e;d=d.replace(ib,"-$1").toLowerCase();if(!(b=a.ownerDocument.defaultView))return B;if(b=b.getComputedStyle(a,null)){e=b.getPropertyValue(d);if(e===""&&!c.contains(a.ownerDocument.documentElement,a))e=c.style(a,d)}return e};if(t.documentElement.currentStyle)aa=function(a,b){var d,e,f=a.currentStyle&&a.currentStyle[b],h=a.style;if(!Fa.test(f)&&jb.test(f)){d=h.left;
|
130 |
-
e=a.runtimeStyle.left;a.runtimeStyle.left=a.currentStyle.left;h.left=b==="fontSize"?"1em":f||0;f=h.pixelLeft+"px";h.left=d;a.runtimeStyle.left=e}return f===""?"auto":f};W=Ga||aa;if(c.expr&&c.expr.filters){c.expr.filters.hidden=function(a){var b=a.offsetHeight;return a.offsetWidth===0&&b===0||!c.support.reliableHiddenOffsets&&(a.style.display||c.css(a,"display"))==="none"};c.expr.filters.visible=function(a){return!c.expr.filters.hidden(a)}}var mb=c.now(),nb=/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
131 |
-
ob=/^(?:select|textarea)/i,pb=/^(?:color|date|datetime|email|hidden|month|number|password|range|search|tel|text|time|url|week)$/i,qb=/^(?:GET|HEAD)$/,Ra=/\[\]$/,T=/\=\?(&|$)/,ja=/\?/,rb=/([?&])_=[^&]*/,sb=/^(\w+:)?\/\/([^\/?#]+)/,tb=/%20/g,ub=/#.*$/,Ha=c.fn.load;c.fn.extend({load:function(a,b,d){if(typeof a!=="string"&&Ha)return Ha.apply(this,arguments);else if(!this.length)return this;var e=a.indexOf(" ");if(e>=0){var f=a.slice(e,a.length);a=a.slice(0,e)}e="GET";if(b)if(c.isFunction(b)){d=b;b=null}else if(typeof b===
|
132 |
-
"object"){b=c.param(b,c.ajaxSettings.traditional);e="POST"}var h=this;c.ajax({url:a,type:e,dataType:"html",data:b,complete:function(l,k){if(k==="success"||k==="notmodified")h.html(f?c("<div>").append(l.responseText.replace(nb,"")).find(f):l.responseText);d&&h.each(d,[l.responseText,k,l])}});return this},serialize:function(){return c.param(this.serializeArray())},serializeArray:function(){return this.map(function(){return this.elements?c.makeArray(this.elements):this}).filter(function(){return this.name&&
|
133 |
-
!this.disabled&&(this.checked||ob.test(this.nodeName)||pb.test(this.type))}).map(function(a,b){var d=c(this).val();return d==null?null:c.isArray(d)?c.map(d,function(e){return{name:b.name,value:e}}):{name:b.name,value:d}}).get()}});c.each("ajaxStart ajaxStop ajaxComplete ajaxError ajaxSuccess ajaxSend".split(" "),function(a,b){c.fn[b]=function(d){return this.bind(b,d)}});c.extend({get:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b=null}return c.ajax({type:"GET",url:a,data:b,success:d,dataType:e})},
|
134 |
-
getScript:function(a,b){return c.get(a,null,b,"script")},getJSON:function(a,b,d){return c.get(a,b,d,"json")},post:function(a,b,d,e){if(c.isFunction(b)){e=e||d;d=b;b={}}return c.ajax({type:"POST",url:a,data:b,success:d,dataType:e})},ajaxSetup:function(a){c.extend(c.ajaxSettings,a)},ajaxSettings:{url:location.href,global:true,type:"GET",contentType:"application/x-www-form-urlencoded",processData:true,async:true,xhr:function(){return new E.XMLHttpRequest},accepts:{xml:"application/xml, text/xml",html:"text/html",
|
135 |
-
script:"text/javascript, application/javascript",json:"application/json, text/javascript",text:"text/plain",_default:"*/*"}},ajax:function(a){var b=c.extend(true,{},c.ajaxSettings,a),d,e,f,h=b.type.toUpperCase(),l=qb.test(h);b.url=b.url.replace(ub,"");b.context=a&&a.context!=null?a.context:b;if(b.data&&b.processData&&typeof b.data!=="string")b.data=c.param(b.data,b.traditional);if(b.dataType==="jsonp"){if(h==="GET")T.test(b.url)||(b.url+=(ja.test(b.url)?"&":"?")+(b.jsonp||"callback")+"=?");else if(!b.data||
|
136 |
-
!T.test(b.data))b.data=(b.data?b.data+"&":"")+(b.jsonp||"callback")+"=?";b.dataType="json"}if(b.dataType==="json"&&(b.data&&T.test(b.data)||T.test(b.url))){d=b.jsonpCallback||"jsonp"+mb++;if(b.data)b.data=(b.data+"").replace(T,"="+d+"$1");b.url=b.url.replace(T,"="+d+"$1");b.dataType="script";var k=E[d];E[d]=function(m){if(c.isFunction(k))k(m);else{E[d]=B;try{delete E[d]}catch(p){}}f=m;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);r&&r.removeChild(A)}}if(b.dataType==="script"&&b.cache===null)b.cache=
|
137 |
-
false;if(b.cache===false&&l){var o=c.now(),x=b.url.replace(rb,"$1_="+o);b.url=x+(x===b.url?(ja.test(b.url)?"&":"?")+"_="+o:"")}if(b.data&&l)b.url+=(ja.test(b.url)?"&":"?")+b.data;b.global&&c.active++===0&&c.event.trigger("ajaxStart");o=(o=sb.exec(b.url))&&(o[1]&&o[1].toLowerCase()!==location.protocol||o[2].toLowerCase()!==location.host);if(b.dataType==="script"&&h==="GET"&&o){var r=t.getElementsByTagName("head")[0]||t.documentElement,A=t.createElement("script");if(b.scriptCharset)A.charset=b.scriptCharset;
|
138 |
-
A.src=b.url;if(!d){var C=false;A.onload=A.onreadystatechange=function(){if(!C&&(!this.readyState||this.readyState==="loaded"||this.readyState==="complete")){C=true;c.handleSuccess(b,w,e,f);c.handleComplete(b,w,e,f);A.onload=A.onreadystatechange=null;r&&A.parentNode&&r.removeChild(A)}}}r.insertBefore(A,r.firstChild);return B}var J=false,w=b.xhr();if(w){b.username?w.open(h,b.url,b.async,b.username,b.password):w.open(h,b.url,b.async);try{if(b.data!=null&&!l||a&&a.contentType)w.setRequestHeader("Content-Type",
|
139 |
-
b.contentType);if(b.ifModified){c.lastModified[b.url]&&w.setRequestHeader("If-Modified-Since",c.lastModified[b.url]);c.etag[b.url]&&w.setRequestHeader("If-None-Match",c.etag[b.url])}o||w.setRequestHeader("X-Requested-With","XMLHttpRequest");w.setRequestHeader("Accept",b.dataType&&b.accepts[b.dataType]?b.accepts[b.dataType]+", */*; q=0.01":b.accepts._default)}catch(I){}if(b.beforeSend&&b.beforeSend.call(b.context,w,b)===false){b.global&&c.active--===1&&c.event.trigger("ajaxStop");w.abort();return false}b.global&&
|
140 |
-
c.triggerGlobal(b,"ajaxSend",[w,b]);var L=w.onreadystatechange=function(m){if(!w||w.readyState===0||m==="abort"){J||c.handleComplete(b,w,e,f);J=true;if(w)w.onreadystatechange=c.noop}else if(!J&&w&&(w.readyState===4||m==="timeout")){J=true;w.onreadystatechange=c.noop;e=m==="timeout"?"timeout":!c.httpSuccess(w)?"error":b.ifModified&&c.httpNotModified(w,b.url)?"notmodified":"success";var p;if(e==="success")try{f=c.httpData(w,b.dataType,b)}catch(q){e="parsererror";p=q}if(e==="success"||e==="notmodified")d||
|
141 |
-
c.handleSuccess(b,w,e,f);else c.handleError(b,w,e,p);d||c.handleComplete(b,w,e,f);m==="timeout"&&w.abort();if(b.async)w=null}};try{var g=w.abort;w.abort=function(){w&&Function.prototype.call.call(g,w);L("abort")}}catch(i){}b.async&&b.timeout>0&&setTimeout(function(){w&&!J&&L("timeout")},b.timeout);try{w.send(l||b.data==null?null:b.data)}catch(n){c.handleError(b,w,null,n);c.handleComplete(b,w,e,f)}b.async||L();return w}},param:function(a,b){var d=[],e=function(h,l){l=c.isFunction(l)?l():l;d[d.length]=
|
142 |
-
encodeURIComponent(h)+"="+encodeURIComponent(l)};if(b===B)b=c.ajaxSettings.traditional;if(c.isArray(a)||a.jquery)c.each(a,function(){e(this.name,this.value)});else for(var f in a)da(f,a[f],b,e);return d.join("&").replace(tb,"+")}});c.extend({active:0,lastModified:{},etag:{},handleError:function(a,b,d,e){a.error&&a.error.call(a.context,b,d,e);a.global&&c.triggerGlobal(a,"ajaxError",[b,a,e])},handleSuccess:function(a,b,d,e){a.success&&a.success.call(a.context,e,d,b);a.global&&c.triggerGlobal(a,"ajaxSuccess",
|
143 |
-
[b,a])},handleComplete:function(a,b,d){a.complete&&a.complete.call(a.context,b,d);a.global&&c.triggerGlobal(a,"ajaxComplete",[b,a]);a.global&&c.active--===1&&c.event.trigger("ajaxStop")},triggerGlobal:function(a,b,d){(a.context&&a.context.url==null?c(a.context):c.event).trigger(b,d)},httpSuccess:function(a){try{return!a.status&&location.protocol==="file:"||a.status>=200&&a.status<300||a.status===304||a.status===1223}catch(b){}return false},httpNotModified:function(a,b){var d=a.getResponseHeader("Last-Modified"),
|
144 |
-
e=a.getResponseHeader("Etag");if(d)c.lastModified[b]=d;if(e)c.etag[b]=e;return a.status===304},httpData:function(a,b,d){var e=a.getResponseHeader("content-type")||"",f=b==="xml"||!b&&e.indexOf("xml")>=0;a=f?a.responseXML:a.responseText;f&&a.documentElement.nodeName==="parsererror"&&c.error("parsererror");if(d&&d.dataFilter)a=d.dataFilter(a,b);if(typeof a==="string")if(b==="json"||!b&&e.indexOf("json")>=0)a=c.parseJSON(a);else if(b==="script"||!b&&e.indexOf("javascript")>=0)c.globalEval(a);return a}});
|
145 |
-
if(E.ActiveXObject)c.ajaxSettings.xhr=function(){if(E.location.protocol!=="file:")try{return new E.XMLHttpRequest}catch(a){}try{return new E.ActiveXObject("Microsoft.XMLHTTP")}catch(b){}};c.support.ajax=!!c.ajaxSettings.xhr();var ea={},vb=/^(?:toggle|show|hide)$/,wb=/^([+\-]=)?([\d+.\-]+)(.*)$/,ba,pa=[["height","marginTop","marginBottom","paddingTop","paddingBottom"],["width","marginLeft","marginRight","paddingLeft","paddingRight"],["opacity"]];c.fn.extend({show:function(a,b,d){if(a||a===0)return this.animate(S("show",
|
146 |
-
3),a,b,d);else{d=0;for(var e=this.length;d<e;d++){a=this[d];b=a.style.display;if(!c.data(a,"olddisplay")&&b==="none")b=a.style.display="";b===""&&c.css(a,"display")==="none"&&c.data(a,"olddisplay",qa(a.nodeName))}for(d=0;d<e;d++){a=this[d];b=a.style.display;if(b===""||b==="none")a.style.display=c.data(a,"olddisplay")||""}return this}},hide:function(a,b,d){if(a||a===0)return this.animate(S("hide",3),a,b,d);else{a=0;for(b=this.length;a<b;a++){d=c.css(this[a],"display");d!=="none"&&c.data(this[a],"olddisplay",
|
147 |
-
d)}for(a=0;a<b;a++)this[a].style.display="none";return this}},_toggle:c.fn.toggle,toggle:function(a,b,d){var e=typeof a==="boolean";if(c.isFunction(a)&&c.isFunction(b))this._toggle.apply(this,arguments);else a==null||e?this.each(function(){var f=e?a:c(this).is(":hidden");c(this)[f?"show":"hide"]()}):this.animate(S("toggle",3),a,b,d);return this},fadeTo:function(a,b,d,e){return this.filter(":hidden").css("opacity",0).show().end().animate({opacity:b},a,d,e)},animate:function(a,b,d,e){var f=c.speed(b,
|
148 |
-
d,e);if(c.isEmptyObject(a))return this.each(f.complete);return this[f.queue===false?"each":"queue"](function(){var h=c.extend({},f),l,k=this.nodeType===1,o=k&&c(this).is(":hidden"),x=this;for(l in a){var r=c.camelCase(l);if(l!==r){a[r]=a[l];delete a[l];l=r}if(a[l]==="hide"&&o||a[l]==="show"&&!o)return h.complete.call(this);if(k&&(l==="height"||l==="width")){h.overflow=[this.style.overflow,this.style.overflowX,this.style.overflowY];if(c.css(this,"display")==="inline"&&c.css(this,"float")==="none")if(c.support.inlineBlockNeedsLayout)if(qa(this.nodeName)===
|
149 |
-
"inline")this.style.display="inline-block";else{this.style.display="inline";this.style.zoom=1}else this.style.display="inline-block"}if(c.isArray(a[l])){(h.specialEasing=h.specialEasing||{})[l]=a[l][1];a[l]=a[l][0]}}if(h.overflow!=null)this.style.overflow="hidden";h.curAnim=c.extend({},a);c.each(a,function(A,C){var J=new c.fx(x,h,A);if(vb.test(C))J[C==="toggle"?o?"show":"hide":C](a);else{var w=wb.exec(C),I=J.cur()||0;if(w){var L=parseFloat(w[2]),g=w[3]||"px";if(g!=="px"){c.style(x,A,(L||1)+g);I=(L||
|
150 |
-
1)/J.cur()*I;c.style(x,A,I+g)}if(w[1])L=(w[1]==="-="?-1:1)*L+I;J.custom(I,L,g)}else J.custom(I,C,"")}});return true})},stop:function(a,b){var d=c.timers;a&&this.queue([]);this.each(function(){for(var e=d.length-1;e>=0;e--)if(d[e].elem===this){b&&d[e](true);d.splice(e,1)}});b||this.dequeue();return this}});c.each({slideDown:S("show",1),slideUp:S("hide",1),slideToggle:S("toggle",1),fadeIn:{opacity:"show"},fadeOut:{opacity:"hide"},fadeToggle:{opacity:"toggle"}},function(a,b){c.fn[a]=function(d,e,f){return this.animate(b,
|
151 |
-
d,e,f)}});c.extend({speed:function(a,b,d){var e=a&&typeof a==="object"?c.extend({},a):{complete:d||!d&&b||c.isFunction(a)&&a,duration:a,easing:d&&b||b&&!c.isFunction(b)&&b};e.duration=c.fx.off?0:typeof e.duration==="number"?e.duration:e.duration in c.fx.speeds?c.fx.speeds[e.duration]:c.fx.speeds._default;e.old=e.complete;e.complete=function(){e.queue!==false&&c(this).dequeue();c.isFunction(e.old)&&e.old.call(this)};return e},easing:{linear:function(a,b,d,e){return d+e*a},swing:function(a,b,d,e){return(-Math.cos(a*
|
152 |
-
Math.PI)/2+0.5)*e+d}},timers:[],fx:function(a,b,d){this.options=b;this.elem=a;this.prop=d;if(!b.orig)b.orig={}}});c.fx.prototype={update:function(){this.options.step&&this.options.step.call(this.elem,this.now,this);(c.fx.step[this.prop]||c.fx.step._default)(this)},cur:function(){if(this.elem[this.prop]!=null&&(!this.elem.style||this.elem.style[this.prop]==null))return this.elem[this.prop];var a=parseFloat(c.css(this.elem,this.prop));return a&&a>-1E4?a:0},custom:function(a,b,d){function e(l){return f.step(l)}
|
153 |
-
var f=this,h=c.fx;this.startTime=c.now();this.start=a;this.end=b;this.unit=d||this.unit||"px";this.now=this.start;this.pos=this.state=0;e.elem=this.elem;if(e()&&c.timers.push(e)&&!ba)ba=setInterval(h.tick,h.interval)},show:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.show=true;this.custom(this.prop==="width"||this.prop==="height"?1:0,this.cur());c(this.elem).show()},hide:function(){this.options.orig[this.prop]=c.style(this.elem,this.prop);this.options.hide=true;
|
154 |
-
this.custom(this.cur(),0)},step:function(a){var b=c.now(),d=true;if(a||b>=this.options.duration+this.startTime){this.now=this.end;this.pos=this.state=1;this.update();this.options.curAnim[this.prop]=true;for(var e in this.options.curAnim)if(this.options.curAnim[e]!==true)d=false;if(d){if(this.options.overflow!=null&&!c.support.shrinkWrapBlocks){var f=this.elem,h=this.options;c.each(["","X","Y"],function(k,o){f.style["overflow"+o]=h.overflow[k]})}this.options.hide&&c(this.elem).hide();if(this.options.hide||
|
155 |
-
this.options.show)for(var l in this.options.curAnim)c.style(this.elem,l,this.options.orig[l]);this.options.complete.call(this.elem)}return false}else{a=b-this.startTime;this.state=a/this.options.duration;b=this.options.easing||(c.easing.swing?"swing":"linear");this.pos=c.easing[this.options.specialEasing&&this.options.specialEasing[this.prop]||b](this.state,a,0,1,this.options.duration);this.now=this.start+(this.end-this.start)*this.pos;this.update()}return true}};c.extend(c.fx,{tick:function(){for(var a=
|
156 |
-
c.timers,b=0;b<a.length;b++)a[b]()||a.splice(b--,1);a.length||c.fx.stop()},interval:13,stop:function(){clearInterval(ba);ba=null},speeds:{slow:600,fast:200,_default:400},step:{opacity:function(a){c.style(a.elem,"opacity",a.now)},_default:function(a){if(a.elem.style&&a.elem.style[a.prop]!=null)a.elem.style[a.prop]=(a.prop==="width"||a.prop==="height"?Math.max(0,a.now):a.now)+a.unit;else a.elem[a.prop]=a.now}}});if(c.expr&&c.expr.filters)c.expr.filters.animated=function(a){return c.grep(c.timers,function(b){return a===
|
157 |
-
b.elem}).length};var xb=/^t(?:able|d|h)$/i,Ia=/^(?:body|html)$/i;c.fn.offset="getBoundingClientRect"in t.documentElement?function(a){var b=this[0],d;if(a)return this.each(function(l){c.offset.setOffset(this,a,l)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);try{d=b.getBoundingClientRect()}catch(e){}var f=b.ownerDocument,h=f.documentElement;if(!d||!c.contains(h,b))return d||{top:0,left:0};b=f.body;f=fa(f);return{top:d.top+(f.pageYOffset||c.support.boxModel&&
|
158 |
-
h.scrollTop||b.scrollTop)-(h.clientTop||b.clientTop||0),left:d.left+(f.pageXOffset||c.support.boxModel&&h.scrollLeft||b.scrollLeft)-(h.clientLeft||b.clientLeft||0)}}:function(a){var b=this[0];if(a)return this.each(function(x){c.offset.setOffset(this,a,x)});if(!b||!b.ownerDocument)return null;if(b===b.ownerDocument.body)return c.offset.bodyOffset(b);c.offset.initialize();var d,e=b.offsetParent,f=b.ownerDocument,h=f.documentElement,l=f.body;d=(f=f.defaultView)?f.getComputedStyle(b,null):b.currentStyle;
|
159 |
-
for(var k=b.offsetTop,o=b.offsetLeft;(b=b.parentNode)&&b!==l&&b!==h;){if(c.offset.supportsFixedPosition&&d.position==="fixed")break;d=f?f.getComputedStyle(b,null):b.currentStyle;k-=b.scrollTop;o-=b.scrollLeft;if(b===e){k+=b.offsetTop;o+=b.offsetLeft;if(c.offset.doesNotAddBorder&&!(c.offset.doesAddBorderForTableAndCells&&xb.test(b.nodeName))){k+=parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}e=b.offsetParent}if(c.offset.subtractsBorderForOverflowNotVisible&&d.overflow!=="visible"){k+=
|
160 |
-
parseFloat(d.borderTopWidth)||0;o+=parseFloat(d.borderLeftWidth)||0}d=d}if(d.position==="relative"||d.position==="static"){k+=l.offsetTop;o+=l.offsetLeft}if(c.offset.supportsFixedPosition&&d.position==="fixed"){k+=Math.max(h.scrollTop,l.scrollTop);o+=Math.max(h.scrollLeft,l.scrollLeft)}return{top:k,left:o}};c.offset={initialize:function(){var a=t.body,b=t.createElement("div"),d,e,f,h=parseFloat(c.css(a,"marginTop"))||0;c.extend(b.style,{position:"absolute",top:0,left:0,margin:0,border:0,width:"1px",
|
161 |
-
height:"1px",visibility:"hidden"});b.innerHTML="<div style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;'><div></div></div><table style='position:absolute;top:0;left:0;margin:0;border:5px solid #000;padding:0;width:1px;height:1px;' cellpadding='0' cellspacing='0'><tr><td></td></tr></table>";a.insertBefore(b,a.firstChild);d=b.firstChild;e=d.firstChild;f=d.nextSibling.firstChild.firstChild;this.doesNotAddBorder=e.offsetTop!==5;this.doesAddBorderForTableAndCells=
|
162 |
-
f.offsetTop===5;e.style.position="fixed";e.style.top="20px";this.supportsFixedPosition=e.offsetTop===20||e.offsetTop===15;e.style.position=e.style.top="";d.style.overflow="hidden";d.style.position="relative";this.subtractsBorderForOverflowNotVisible=e.offsetTop===-5;this.doesNotIncludeMarginInBodyOffset=a.offsetTop!==h;a.removeChild(b);c.offset.initialize=c.noop},bodyOffset:function(a){var b=a.offsetTop,d=a.offsetLeft;c.offset.initialize();if(c.offset.doesNotIncludeMarginInBodyOffset){b+=parseFloat(c.css(a,
|
163 |
-
"marginTop"))||0;d+=parseFloat(c.css(a,"marginLeft"))||0}return{top:b,left:d}},setOffset:function(a,b,d){var e=c.css(a,"position");if(e==="static")a.style.position="relative";var f=c(a),h=f.offset(),l=c.css(a,"top"),k=c.css(a,"left"),o=e==="absolute"&&c.inArray("auto",[l,k])>-1;e={};var x={};if(o)x=f.position();l=o?x.top:parseInt(l,10)||0;k=o?x.left:parseInt(k,10)||0;if(c.isFunction(b))b=b.call(a,d,h);if(b.top!=null)e.top=b.top-h.top+l;if(b.left!=null)e.left=b.left-h.left+k;"using"in b?b.using.call(a,
|
164 |
-
e):f.css(e)}};c.fn.extend({position:function(){if(!this[0])return null;var a=this[0],b=this.offsetParent(),d=this.offset(),e=Ia.test(b[0].nodeName)?{top:0,left:0}:b.offset();d.top-=parseFloat(c.css(a,"marginTop"))||0;d.left-=parseFloat(c.css(a,"marginLeft"))||0;e.top+=parseFloat(c.css(b[0],"borderTopWidth"))||0;e.left+=parseFloat(c.css(b[0],"borderLeftWidth"))||0;return{top:d.top-e.top,left:d.left-e.left}},offsetParent:function(){return this.map(function(){for(var a=this.offsetParent||t.body;a&&!Ia.test(a.nodeName)&&
|
165 |
-
c.css(a,"position")==="static";)a=a.offsetParent;return a})}});c.each(["Left","Top"],function(a,b){var d="scroll"+b;c.fn[d]=function(e){var f=this[0],h;if(!f)return null;if(e!==B)return this.each(function(){if(h=fa(this))h.scrollTo(!a?e:c(h).scrollLeft(),a?e:c(h).scrollTop());else this[d]=e});else return(h=fa(f))?"pageXOffset"in h?h[a?"pageYOffset":"pageXOffset"]:c.support.boxModel&&h.document.documentElement[d]||h.document.body[d]:f[d]}});c.each(["Height","Width"],function(a,b){var d=b.toLowerCase();
|
166 |
-
c.fn["inner"+b]=function(){return this[0]?parseFloat(c.css(this[0],d,"padding")):null};c.fn["outer"+b]=function(e){return this[0]?parseFloat(c.css(this[0],d,e?"margin":"border")):null};c.fn[d]=function(e){var f=this[0];if(!f)return e==null?null:this;if(c.isFunction(e))return this.each(function(l){var k=c(this);k[d](e.call(this,l,k[d]()))});if(c.isWindow(f))return f.document.compatMode==="CSS1Compat"&&f.document.documentElement["client"+b]||f.document.body["client"+b];else if(f.nodeType===9)return Math.max(f.documentElement["client"+
|
167 |
-
b],f.body["scroll"+b],f.documentElement["scroll"+b],f.body["offset"+b],f.documentElement["offset"+b]);else if(e===B){f=c.css(f,d);var h=parseFloat(f);return c.isNaN(h)?f:h}else return this.css(d,typeof e==="string"?e:e+"px")}})})(window);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
javascript/jquery-ui-1.8.9.custom.min.js
DELETED
@@ -1,781 +0,0 @@
|
|
1 |
-
/*!
|
2 |
-
* jQuery UI 1.8.9
|
3 |
-
*
|
4 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
5 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
6 |
-
* http://jquery.org/license
|
7 |
-
*
|
8 |
-
* http://docs.jquery.com/UI
|
9 |
-
*/
|
10 |
-
(function(c,j){function k(a){return!c(a).parents().andSelf().filter(function(){return c.curCSS(this,"visibility")==="hidden"||c.expr.filters.hidden(this)}).length}c.ui=c.ui||{};if(!c.ui.version){c.extend(c.ui,{version:"1.8.9",keyCode:{ALT:18,BACKSPACE:8,CAPS_LOCK:20,COMMA:188,COMMAND:91,COMMAND_LEFT:91,COMMAND_RIGHT:93,CONTROL:17,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,INSERT:45,LEFT:37,MENU:93,NUMPAD_ADD:107,NUMPAD_DECIMAL:110,NUMPAD_DIVIDE:111,NUMPAD_ENTER:108,NUMPAD_MULTIPLY:106,
|
11 |
-
NUMPAD_SUBTRACT:109,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SHIFT:16,SPACE:32,TAB:9,UP:38,WINDOWS:91}});c.fn.extend({_focus:c.fn.focus,focus:function(a,b){return typeof a==="number"?this.each(function(){var d=this;setTimeout(function(){c(d).focus();b&&b.call(d)},a)}):this._focus.apply(this,arguments)},scrollParent:function(){var a;a=c.browser.msie&&/(static|relative)/.test(this.css("position"))||/absolute/.test(this.css("position"))?this.parents().filter(function(){return/(relative|absolute|fixed)/.test(c.curCSS(this,
|
12 |
-
"position",1))&&/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0):this.parents().filter(function(){return/(auto|scroll)/.test(c.curCSS(this,"overflow",1)+c.curCSS(this,"overflow-y",1)+c.curCSS(this,"overflow-x",1))}).eq(0);return/fixed/.test(this.css("position"))||!a.length?c(document):a},zIndex:function(a){if(a!==j)return this.css("zIndex",a);if(this.length){a=c(this[0]);for(var b;a.length&&a[0]!==document;){b=a.css("position");
|
13 |
-
if(b==="absolute"||b==="relative"||b==="fixed"){b=parseInt(a.css("zIndex"),10);if(!isNaN(b)&&b!==0)return b}a=a.parent()}}return 0},disableSelection:function(){return this.bind((c.support.selectstart?"selectstart":"mousedown")+".ui-disableSelection",function(a){a.preventDefault()})},enableSelection:function(){return this.unbind(".ui-disableSelection")}});c.each(["Width","Height"],function(a,b){function d(f,g,l,m){c.each(e,function(){g-=parseFloat(c.curCSS(f,"padding"+this,true))||0;if(l)g-=parseFloat(c.curCSS(f,
|
14 |
-
"border"+this+"Width",true))||0;if(m)g-=parseFloat(c.curCSS(f,"margin"+this,true))||0});return g}var e=b==="Width"?["Left","Right"]:["Top","Bottom"],h=b.toLowerCase(),i={innerWidth:c.fn.innerWidth,innerHeight:c.fn.innerHeight,outerWidth:c.fn.outerWidth,outerHeight:c.fn.outerHeight};c.fn["inner"+b]=function(f){if(f===j)return i["inner"+b].call(this);return this.each(function(){c(this).css(h,d(this,f)+"px")})};c.fn["outer"+b]=function(f,g){if(typeof f!=="number")return i["outer"+b].call(this,f);return this.each(function(){c(this).css(h,
|
15 |
-
d(this,f,true,g)+"px")})}});c.extend(c.expr[":"],{data:function(a,b,d){return!!c.data(a,d[3])},focusable:function(a){var b=a.nodeName.toLowerCase(),d=c.attr(a,"tabindex");if("area"===b){b=a.parentNode;d=b.name;if(!a.href||!d||b.nodeName.toLowerCase()!=="map")return false;a=c("img[usemap=#"+d+"]")[0];return!!a&&k(a)}return(/input|select|textarea|button|object/.test(b)?!a.disabled:"a"==b?a.href||!isNaN(d):!isNaN(d))&&k(a)},tabbable:function(a){var b=c.attr(a,"tabindex");return(isNaN(b)||b>=0)&&c(a).is(":focusable")}});
|
16 |
-
c(function(){var a=document.body,b=a.appendChild(b=document.createElement("div"));c.extend(b.style,{minHeight:"100px",height:"auto",padding:0,borderWidth:0});c.support.minHeight=b.offsetHeight===100;c.support.selectstart="onselectstart"in b;a.removeChild(b).style.display="none"});c.extend(c.ui,{plugin:{add:function(a,b,d){a=c.ui[a].prototype;for(var e in d){a.plugins[e]=a.plugins[e]||[];a.plugins[e].push([b,d[e]])}},call:function(a,b,d){if((b=a.plugins[b])&&a.element[0].parentNode)for(var e=0;e<b.length;e++)a.options[b[e][0]]&&
|
17 |
-
b[e][1].apply(a.element,d)}},contains:function(a,b){return document.compareDocumentPosition?a.compareDocumentPosition(b)&16:a!==b&&a.contains(b)},hasScroll:function(a,b){if(c(a).css("overflow")==="hidden")return false;b=b&&b==="left"?"scrollLeft":"scrollTop";var d=false;if(a[b]>0)return true;a[b]=1;d=a[b]>0;a[b]=0;return d},isOverAxis:function(a,b,d){return a>b&&a<b+d},isOver:function(a,b,d,e,h,i){return c.ui.isOverAxis(a,d,h)&&c.ui.isOverAxis(b,e,i)}})}})(jQuery);
|
18 |
-
;/*!
|
19 |
-
* jQuery UI Widget 1.8.9
|
20 |
-
*
|
21 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
22 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
23 |
-
* http://jquery.org/license
|
24 |
-
*
|
25 |
-
* http://docs.jquery.com/UI/Widget
|
26 |
-
*/
|
27 |
-
(function(b,j){if(b.cleanData){var k=b.cleanData;b.cleanData=function(a){for(var c=0,d;(d=a[c])!=null;c++)b(d).triggerHandler("remove");k(a)}}else{var l=b.fn.remove;b.fn.remove=function(a,c){return this.each(function(){if(!c)if(!a||b.filter(a,[this]).length)b("*",this).add([this]).each(function(){b(this).triggerHandler("remove")});return l.call(b(this),a,c)})}}b.widget=function(a,c,d){var e=a.split(".")[0],f;a=a.split(".")[1];f=e+"-"+a;if(!d){d=c;c=b.Widget}b.expr[":"][f]=function(h){return!!b.data(h,
|
28 |
-
a)};b[e]=b[e]||{};b[e][a]=function(h,g){arguments.length&&this._createWidget(h,g)};c=new c;c.options=b.extend(true,{},c.options);b[e][a].prototype=b.extend(true,c,{namespace:e,widgetName:a,widgetEventPrefix:b[e][a].prototype.widgetEventPrefix||a,widgetBaseClass:f},d);b.widget.bridge(a,b[e][a])};b.widget.bridge=function(a,c){b.fn[a]=function(d){var e=typeof d==="string",f=Array.prototype.slice.call(arguments,1),h=this;d=!e&&f.length?b.extend.apply(null,[true,d].concat(f)):d;if(e&&d.charAt(0)==="_")return h;
|
29 |
-
e?this.each(function(){var g=b.data(this,a),i=g&&b.isFunction(g[d])?g[d].apply(g,f):g;if(i!==g&&i!==j){h=i;return false}}):this.each(function(){var g=b.data(this,a);g?g.option(d||{})._init():b.data(this,a,new c(d,this))});return h}};b.Widget=function(a,c){arguments.length&&this._createWidget(a,c)};b.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",options:{disabled:false},_createWidget:function(a,c){b.data(c,this.widgetName,this);this.element=b(c);this.options=b.extend(true,{},this.options,
|
30 |
-
this._getCreateOptions(),a);var d=this;this.element.bind("remove."+this.widgetName,function(){d.destroy()});this._create();this._trigger("create");this._init()},_getCreateOptions:function(){return b.metadata&&b.metadata.get(this.element[0])[this.widgetName]},_create:function(){},_init:function(){},destroy:function(){this.element.unbind("."+this.widgetName).removeData(this.widgetName);this.widget().unbind("."+this.widgetName).removeAttr("aria-disabled").removeClass(this.widgetBaseClass+"-disabled ui-state-disabled")},
|
31 |
-
widget:function(){return this.element},option:function(a,c){var d=a;if(arguments.length===0)return b.extend({},this.options);if(typeof a==="string"){if(c===j)return this.options[a];d={};d[a]=c}this._setOptions(d);return this},_setOptions:function(a){var c=this;b.each(a,function(d,e){c._setOption(d,e)});return this},_setOption:function(a,c){this.options[a]=c;if(a==="disabled")this.widget()[c?"addClass":"removeClass"](this.widgetBaseClass+"-disabled ui-state-disabled").attr("aria-disabled",c);return this},
|
32 |
-
enable:function(){return this._setOption("disabled",false)},disable:function(){return this._setOption("disabled",true)},_trigger:function(a,c,d){var e=this.options[a];c=b.Event(c);c.type=(a===this.widgetEventPrefix?a:this.widgetEventPrefix+a).toLowerCase();d=d||{};if(c.originalEvent){a=b.event.props.length;for(var f;a;){f=b.event.props[--a];c[f]=c.originalEvent[f]}}this.element.trigger(c,d);return!(b.isFunction(e)&&e.call(this.element[0],c,d)===false||c.isDefaultPrevented())}}})(jQuery);
|
33 |
-
;/*!
|
34 |
-
* jQuery UI Mouse 1.8.9
|
35 |
-
*
|
36 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
37 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
38 |
-
* http://jquery.org/license
|
39 |
-
*
|
40 |
-
* http://docs.jquery.com/UI/Mouse
|
41 |
-
*
|
42 |
-
* Depends:
|
43 |
-
* jquery.ui.widget.js
|
44 |
-
*/
|
45 |
-
(function(c){c.widget("ui.mouse",{options:{cancel:":input,option",distance:1,delay:0},_mouseInit:function(){var a=this;this.element.bind("mousedown."+this.widgetName,function(b){return a._mouseDown(b)}).bind("click."+this.widgetName,function(b){if(true===c.data(b.target,a.widgetName+".preventClickEvent")){c.removeData(b.target,a.widgetName+".preventClickEvent");b.stopImmediatePropagation();return false}});this.started=false},_mouseDestroy:function(){this.element.unbind("."+this.widgetName)},_mouseDown:function(a){a.originalEvent=
|
46 |
-
a.originalEvent||{};if(!a.originalEvent.mouseHandled){this._mouseStarted&&this._mouseUp(a);this._mouseDownEvent=a;var b=this,e=a.which==1,f=typeof this.options.cancel=="string"?c(a.target).parents().add(a.target).filter(this.options.cancel).length:false;if(!e||f||!this._mouseCapture(a))return true;this.mouseDelayMet=!this.options.delay;if(!this.mouseDelayMet)this._mouseDelayTimer=setTimeout(function(){b.mouseDelayMet=true},this.options.delay);if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a)){this._mouseStarted=
|
47 |
-
this._mouseStart(a)!==false;if(!this._mouseStarted){a.preventDefault();return true}}this._mouseMoveDelegate=function(d){return b._mouseMove(d)};this._mouseUpDelegate=function(d){return b._mouseUp(d)};c(document).bind("mousemove."+this.widgetName,this._mouseMoveDelegate).bind("mouseup."+this.widgetName,this._mouseUpDelegate);a.preventDefault();return a.originalEvent.mouseHandled=true}},_mouseMove:function(a){if(c.browser.msie&&!(document.documentMode>=9)&&!a.button)return this._mouseUp(a);if(this._mouseStarted){this._mouseDrag(a);
|
48 |
-
return a.preventDefault()}if(this._mouseDistanceMet(a)&&this._mouseDelayMet(a))(this._mouseStarted=this._mouseStart(this._mouseDownEvent,a)!==false)?this._mouseDrag(a):this._mouseUp(a);return!this._mouseStarted},_mouseUp:function(a){c(document).unbind("mousemove."+this.widgetName,this._mouseMoveDelegate).unbind("mouseup."+this.widgetName,this._mouseUpDelegate);if(this._mouseStarted){this._mouseStarted=false;a.target==this._mouseDownEvent.target&&c.data(a.target,this.widgetName+".preventClickEvent",
|
49 |
-
true);this._mouseStop(a)}return false},_mouseDistanceMet:function(a){return Math.max(Math.abs(this._mouseDownEvent.pageX-a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return true}})})(jQuery);
|
50 |
-
;/*
|
51 |
-
* jQuery UI Position 1.8.9
|
52 |
-
*
|
53 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
54 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
55 |
-
* http://jquery.org/license
|
56 |
-
*
|
57 |
-
* http://docs.jquery.com/UI/Position
|
58 |
-
*/
|
59 |
-
(function(c){c.ui=c.ui||{};var n=/left|center|right/,o=/top|center|bottom/,t=c.fn.position,u=c.fn.offset;c.fn.position=function(b){if(!b||!b.of)return t.apply(this,arguments);b=c.extend({},b);var a=c(b.of),d=a[0],g=(b.collision||"flip").split(" "),e=b.offset?b.offset.split(" "):[0,0],h,k,j;if(d.nodeType===9){h=a.width();k=a.height();j={top:0,left:0}}else if(d.setTimeout){h=a.width();k=a.height();j={top:a.scrollTop(),left:a.scrollLeft()}}else if(d.preventDefault){b.at="left top";h=k=0;j={top:b.of.pageY,
|
60 |
-
left:b.of.pageX}}else{h=a.outerWidth();k=a.outerHeight();j=a.offset()}c.each(["my","at"],function(){var f=(b[this]||"").split(" ");if(f.length===1)f=n.test(f[0])?f.concat(["center"]):o.test(f[0])?["center"].concat(f):["center","center"];f[0]=n.test(f[0])?f[0]:"center";f[1]=o.test(f[1])?f[1]:"center";b[this]=f});if(g.length===1)g[1]=g[0];e[0]=parseInt(e[0],10)||0;if(e.length===1)e[1]=e[0];e[1]=parseInt(e[1],10)||0;if(b.at[0]==="right")j.left+=h;else if(b.at[0]==="center")j.left+=h/2;if(b.at[1]==="bottom")j.top+=
|
61 |
-
k;else if(b.at[1]==="center")j.top+=k/2;j.left+=e[0];j.top+=e[1];return this.each(function(){var f=c(this),l=f.outerWidth(),m=f.outerHeight(),p=parseInt(c.curCSS(this,"marginLeft",true))||0,q=parseInt(c.curCSS(this,"marginTop",true))||0,v=l+p+(parseInt(c.curCSS(this,"marginRight",true))||0),w=m+q+(parseInt(c.curCSS(this,"marginBottom",true))||0),i=c.extend({},j),r;if(b.my[0]==="right")i.left-=l;else if(b.my[0]==="center")i.left-=l/2;if(b.my[1]==="bottom")i.top-=m;else if(b.my[1]==="center")i.top-=
|
62 |
-
m/2;i.left=Math.round(i.left);i.top=Math.round(i.top);r={left:i.left-p,top:i.top-q};c.each(["left","top"],function(s,x){c.ui.position[g[s]]&&c.ui.position[g[s]][x](i,{targetWidth:h,targetHeight:k,elemWidth:l,elemHeight:m,collisionPosition:r,collisionWidth:v,collisionHeight:w,offset:e,my:b.my,at:b.at})});c.fn.bgiframe&&f.bgiframe();f.offset(c.extend(i,{using:b.using}))})};c.ui.position={fit:{left:function(b,a){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();b.left=
|
63 |
-
d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];b.left+=
|
64 |
-
a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=c(b),
|
65 |
-
g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);
|
66 |
-
;/*
|
67 |
-
* jQuery UI Draggable 1.8.9
|
68 |
-
*
|
69 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
70 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
71 |
-
* http://jquery.org/license
|
72 |
-
*
|
73 |
-
* http://docs.jquery.com/UI/Draggables
|
74 |
-
*
|
75 |
-
* Depends:
|
76 |
-
* jquery.ui.core.js
|
77 |
-
* jquery.ui.mouse.js
|
78 |
-
* jquery.ui.widget.js
|
79 |
-
*/
|
80 |
-
(function(d){d.widget("ui.draggable",d.ui.mouse,{widgetEventPrefix:"drag",options:{addClasses:true,appendTo:"parent",axis:false,connectToSortable:false,containment:false,cursor:"auto",cursorAt:false,grid:false,handle:false,helper:"original",iframeFix:false,opacity:false,refreshPositions:false,revert:false,revertDuration:500,scope:"default",scroll:true,scrollSensitivity:20,scrollSpeed:20,snap:false,snapMode:"both",snapTolerance:20,stack:false,zIndex:false},_create:function(){if(this.options.helper==
|
81 |
-
"original"&&!/^(?:r|a|f)/.test(this.element.css("position")))this.element[0].style.position="relative";this.options.addClasses&&this.element.addClass("ui-draggable");this.options.disabled&&this.element.addClass("ui-draggable-disabled");this._mouseInit()},destroy:function(){if(this.element.data("draggable")){this.element.removeData("draggable").unbind(".draggable").removeClass("ui-draggable ui-draggable-dragging ui-draggable-disabled");this._mouseDestroy();return this}},_mouseCapture:function(a){var b=
|
82 |
-
this.options;if(this.helper||b.disabled||d(a.target).is(".ui-resizable-handle"))return false;this.handle=this._getHandle(a);if(!this.handle)return false;return true},_mouseStart:function(a){var b=this.options;this.helper=this._createHelper(a);this._cacheHelperProportions();if(d.ui.ddmanager)d.ui.ddmanager.current=this;this._cacheMargins();this.cssPosition=this.helper.css("position");this.scrollParent=this.helper.scrollParent();this.offset=this.positionAbs=this.element.offset();this.offset={top:this.offset.top-
|
83 |
-
this.margins.top,left:this.offset.left-this.margins.left};d.extend(this.offset,{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this.position=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);b.containment&&this._setContainment();if(this._trigger("start",a)===false){this._clear();return false}this._cacheHelperProportions();
|
84 |
-
d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.helper.addClass("ui-draggable-dragging");this._mouseDrag(a,true);return true},_mouseDrag:function(a,b){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");if(!b){b=this._uiHash();if(this._trigger("drag",a,b)===false){this._mouseUp({});return false}this.position=b.position}if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+"px";if(!this.options.axis||
|
85 |
-
this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);return false},_mouseStop:function(a){var b=false;if(d.ui.ddmanager&&!this.options.dropBehaviour)b=d.ui.ddmanager.drop(this,a);if(this.dropped){b=this.dropped;this.dropped=false}if((!this.element[0]||!this.element[0].parentNode)&&this.options.helper=="original")return false;if(this.options.revert=="invalid"&&!b||this.options.revert=="valid"&&b||this.options.revert===true||d.isFunction(this.options.revert)&&
|
86 |
-
this.options.revert.call(this.element,b)){var c=this;d(this.helper).animate(this.originalPosition,parseInt(this.options.revertDuration,10),function(){c._trigger("stop",a)!==false&&c._clear()})}else this._trigger("stop",a)!==false&&this._clear();return false},cancel:function(){this.helper.is(".ui-draggable-dragging")?this._mouseUp({}):this._clear();return this},_getHandle:function(a){var b=!this.options.handle||!d(this.options.handle,this.element).length?true:false;d(this.options.handle,this.element).find("*").andSelf().each(function(){if(this==
|
87 |
-
a.target)b=true});return b},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a])):b.helper=="clone"?this.element.clone():this.element;a.parents("body").length||a.appendTo(b.appendTo=="parent"?this.element[0].parentNode:b.appendTo);a[0]!=this.element[0]&&!/(fixed|absolute)/.test(a.css("position"))&&a.css("position","absolute");return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||
|
88 |
-
0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],
|
89 |
-
this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.element.position();return{top:a.top-
|
90 |
-
(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.element.css("marginLeft"),10)||0,top:parseInt(this.element.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions={width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment==
|
91 |
-
"parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[(a.containment=="document"?0:d(window).scrollLeft())-this.offset.relative.left-this.offset.parent.left,(a.containment=="document"?0:d(window).scrollTop())-this.offset.relative.top-this.offset.parent.top,(a.containment=="document"?0:d(window).scrollLeft())+d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(a.containment=="document"?
|
92 |
-
0:d(window).scrollTop())+(d(a.containment=="document"?document:window).height()||document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)&&a.containment.constructor!=Array){var b=d(a.containment)[0];if(b){a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),
|
93 |
-
10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}}else if(a.containment.constructor==
|
94 |
-
Array)this.containment=a.containment},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():
|
95 |
-
f?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,f=/(html|body)/i.test(c[0].tagName),e=a.pageX,g=a.pageY;
|
96 |
-
if(this.originalPosition){if(this.containment){if(a.pageX-this.offset.click.left<this.containment[0])e=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])e=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/
|
97 |
-
b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;e=this.originalPageX+Math.round((e-this.originalPageX)/b.grid[0])*b.grid[0];e=this.containment?!(e-this.offset.click.left<this.containment[0]||e-this.offset.click.left>this.containment[2])?e:!(e-this.offset.click.left<this.containment[0])?e-b.grid[0]:e+b.grid[0]:e}}return{top:g-this.offset.click.top-
|
98 |
-
this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():f?0:c.scrollTop()),left:e-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&d.browser.version<526&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():f?0:c.scrollLeft())}},_clear:function(){this.helper.removeClass("ui-draggable-dragging");this.helper[0]!=
|
99 |
-
this.element[0]&&!this.cancelHelperRemoval&&this.helper.remove();this.helper=null;this.cancelHelperRemoval=false},_trigger:function(a,b,c){c=c||this._uiHash();d.ui.plugin.call(this,a,[b,c]);if(a=="drag")this.positionAbs=this._convertPositionTo("absolute");return d.Widget.prototype._trigger.call(this,a,b,c)},plugins:{},_uiHash:function(){return{helper:this.helper,position:this.position,originalPosition:this.originalPosition,offset:this.positionAbs}}});d.extend(d.ui.draggable,{version:"1.8.9"});
|
100 |
-
d.ui.plugin.add("draggable","connectToSortable",{start:function(a,b){var c=d(this).data("draggable"),f=c.options,e=d.extend({},b,{item:c.element});c.sortables=[];d(f.connectToSortable).each(function(){var g=d.data(this,"sortable");if(g&&!g.options.disabled){c.sortables.push({instance:g,shouldRevert:g.options.revert});g._refreshItems();g._trigger("activate",a,e)}})},stop:function(a,b){var c=d(this).data("draggable"),f=d.extend({},b,{item:c.element});d.each(c.sortables,function(){if(this.instance.isOver){this.instance.isOver=
|
101 |
-
0;c.cancelHelperRemoval=true;this.instance.cancelHelperRemoval=false;if(this.shouldRevert)this.instance.options.revert=true;this.instance._mouseStop(a);this.instance.options.helper=this.instance.options._helper;c.options.helper=="original"&&this.instance.currentItem.css({top:"auto",left:"auto"})}else{this.instance.cancelHelperRemoval=false;this.instance._trigger("deactivate",a,f)}})},drag:function(a,b){var c=d(this).data("draggable"),f=this;d.each(c.sortables,function(){this.instance.positionAbs=
|
102 |
-
c.positionAbs;this.instance.helperProportions=c.helperProportions;this.instance.offset.click=c.offset.click;if(this.instance._intersectsWith(this.instance.containerCache)){if(!this.instance.isOver){this.instance.isOver=1;this.instance.currentItem=d(f).clone().appendTo(this.instance.element).data("sortable-item",true);this.instance.options._helper=this.instance.options.helper;this.instance.options.helper=function(){return b.helper[0]};a.target=this.instance.currentItem[0];this.instance._mouseCapture(a,
|
103 |
-
true);this.instance._mouseStart(a,true,true);this.instance.offset.click.top=c.offset.click.top;this.instance.offset.click.left=c.offset.click.left;this.instance.offset.parent.left-=c.offset.parent.left-this.instance.offset.parent.left;this.instance.offset.parent.top-=c.offset.parent.top-this.instance.offset.parent.top;c._trigger("toSortable",a);c.dropped=this.instance.element;c.currentItem=c.element;this.instance.fromOutside=c}this.instance.currentItem&&this.instance._mouseDrag(a)}else if(this.instance.isOver){this.instance.isOver=
|
104 |
-
0;this.instance.cancelHelperRemoval=true;this.instance.options.revert=false;this.instance._trigger("out",a,this.instance._uiHash(this.instance));this.instance._mouseStop(a,true);this.instance.options.helper=this.instance.options._helper;this.instance.currentItem.remove();this.instance.placeholder&&this.instance.placeholder.remove();c._trigger("fromSortable",a);c.dropped=false}})}});d.ui.plugin.add("draggable","cursor",{start:function(){var a=d("body"),b=d(this).data("draggable").options;if(a.css("cursor"))b._cursor=
|
105 |
-
a.css("cursor");a.css("cursor",b.cursor)},stop:function(){var a=d(this).data("draggable").options;a._cursor&&d("body").css("cursor",a._cursor)}});d.ui.plugin.add("draggable","iframeFix",{start:function(){var a=d(this).data("draggable").options;d(a.iframeFix===true?"iframe":a.iframeFix).each(function(){d('<div class="ui-draggable-iframeFix" style="background: #fff;"></div>').css({width:this.offsetWidth+"px",height:this.offsetHeight+"px",position:"absolute",opacity:"0.001",zIndex:1E3}).css(d(this).offset()).appendTo("body")})},
|
106 |
-
stop:function(){d("div.ui-draggable-iframeFix").each(function(){this.parentNode.removeChild(this)})}});d.ui.plugin.add("draggable","opacity",{start:function(a,b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("opacity"))b._opacity=a.css("opacity");a.css("opacity",b.opacity)},stop:function(a,b){a=d(this).data("draggable").options;a._opacity&&d(b.helper).css("opacity",a._opacity)}});d.ui.plugin.add("draggable","scroll",{start:function(){var a=d(this).data("draggable");if(a.scrollParent[0]!=
|
107 |
-
document&&a.scrollParent[0].tagName!="HTML")a.overflowOffset=a.scrollParent.offset()},drag:function(a){var b=d(this).data("draggable"),c=b.options,f=false;if(b.scrollParent[0]!=document&&b.scrollParent[0].tagName!="HTML"){if(!c.axis||c.axis!="x")if(b.overflowOffset.top+b.scrollParent[0].offsetHeight-a.pageY<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop+c.scrollSpeed;else if(a.pageY-b.overflowOffset.top<c.scrollSensitivity)b.scrollParent[0].scrollTop=f=b.scrollParent[0].scrollTop-
|
108 |
-
c.scrollSpeed;if(!c.axis||c.axis!="y")if(b.overflowOffset.left+b.scrollParent[0].offsetWidth-a.pageX<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft+c.scrollSpeed;else if(a.pageX-b.overflowOffset.left<c.scrollSensitivity)b.scrollParent[0].scrollLeft=f=b.scrollParent[0].scrollLeft-c.scrollSpeed}else{if(!c.axis||c.axis!="x")if(a.pageY-d(document).scrollTop()<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()-c.scrollSpeed);else if(d(window).height()-
|
109 |
-
(a.pageY-d(document).scrollTop())<c.scrollSensitivity)f=d(document).scrollTop(d(document).scrollTop()+c.scrollSpeed);if(!c.axis||c.axis!="y")if(a.pageX-d(document).scrollLeft()<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()-c.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<c.scrollSensitivity)f=d(document).scrollLeft(d(document).scrollLeft()+c.scrollSpeed)}f!==false&&d.ui.ddmanager&&!c.dropBehaviour&&d.ui.ddmanager.prepareOffsets(b,a)}});d.ui.plugin.add("draggable",
|
110 |
-
"snap",{start:function(){var a=d(this).data("draggable"),b=a.options;a.snapElements=[];d(b.snap.constructor!=String?b.snap.items||":data(draggable)":b.snap).each(function(){var c=d(this),f=c.offset();this!=a.element[0]&&a.snapElements.push({item:this,width:c.outerWidth(),height:c.outerHeight(),top:f.top,left:f.left})})},drag:function(a,b){for(var c=d(this).data("draggable"),f=c.options,e=f.snapTolerance,g=b.offset.left,n=g+c.helperProportions.width,m=b.offset.top,o=m+c.helperProportions.height,h=
|
111 |
-
c.snapElements.length-1;h>=0;h--){var i=c.snapElements[h].left,k=i+c.snapElements[h].width,j=c.snapElements[h].top,l=j+c.snapElements[h].height;if(i-e<g&&g<k+e&&j-e<m&&m<l+e||i-e<g&&g<k+e&&j-e<o&&o<l+e||i-e<n&&n<k+e&&j-e<m&&m<l+e||i-e<n&&n<k+e&&j-e<o&&o<l+e){if(f.snapMode!="inner"){var p=Math.abs(j-o)<=e,q=Math.abs(l-m)<=e,r=Math.abs(i-n)<=e,s=Math.abs(k-g)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:j-c.helperProportions.height,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",
|
112 |
-
{top:l,left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i-c.helperProportions.width}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k}).left-c.margins.left}var t=p||q||r||s;if(f.snapMode!="outer"){p=Math.abs(j-m)<=e;q=Math.abs(l-o)<=e;r=Math.abs(i-g)<=e;s=Math.abs(k-n)<=e;if(p)b.position.top=c._convertPositionTo("relative",{top:j,left:0}).top-c.margins.top;if(q)b.position.top=c._convertPositionTo("relative",{top:l-c.helperProportions.height,
|
113 |
-
left:0}).top-c.margins.top;if(r)b.position.left=c._convertPositionTo("relative",{top:0,left:i}).left-c.margins.left;if(s)b.position.left=c._convertPositionTo("relative",{top:0,left:k-c.helperProportions.width}).left-c.margins.left}if(!c.snapElements[h].snapping&&(p||q||r||s||t))c.options.snap.snap&&c.options.snap.snap.call(c.element,a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=p||q||r||s||t}else{c.snapElements[h].snapping&&c.options.snap.release&&c.options.snap.release.call(c.element,
|
114 |
-
a,d.extend(c._uiHash(),{snapItem:c.snapElements[h].item}));c.snapElements[h].snapping=false}}}});d.ui.plugin.add("draggable","stack",{start:function(){var a=d(this).data("draggable").options;a=d.makeArray(d(a.stack)).sort(function(c,f){return(parseInt(d(c).css("zIndex"),10)||0)-(parseInt(d(f).css("zIndex"),10)||0)});if(a.length){var b=parseInt(a[0].style.zIndex)||0;d(a).each(function(c){this.style.zIndex=b+c});this[0].style.zIndex=b+a.length}}});d.ui.plugin.add("draggable","zIndex",{start:function(a,
|
115 |
-
b){a=d(b.helper);b=d(this).data("draggable").options;if(a.css("zIndex"))b._zIndex=a.css("zIndex");a.css("zIndex",b.zIndex)},stop:function(a,b){a=d(this).data("draggable").options;a._zIndex&&d(b.helper).css("zIndex",a._zIndex)}})})(jQuery);
|
116 |
-
;/*
|
117 |
-
* jQuery UI Droppable 1.8.9
|
118 |
-
*
|
119 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
120 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
121 |
-
* http://jquery.org/license
|
122 |
-
*
|
123 |
-
* http://docs.jquery.com/UI/Droppables
|
124 |
-
*
|
125 |
-
* Depends:
|
126 |
-
* jquery.ui.core.js
|
127 |
-
* jquery.ui.widget.js
|
128 |
-
* jquery.ui.mouse.js
|
129 |
-
* jquery.ui.draggable.js
|
130 |
-
*/
|
131 |
-
(function(d){d.widget("ui.droppable",{widgetEventPrefix:"drop",options:{accept:"*",activeClass:false,addClasses:true,greedy:false,hoverClass:false,scope:"default",tolerance:"intersect"},_create:function(){var a=this.options,b=a.accept;this.isover=0;this.isout=1;this.accept=d.isFunction(b)?b:function(c){return c.is(b)};this.proportions={width:this.element[0].offsetWidth,height:this.element[0].offsetHeight};d.ui.ddmanager.droppables[a.scope]=d.ui.ddmanager.droppables[a.scope]||[];d.ui.ddmanager.droppables[a.scope].push(this);
|
132 |
-
a.addClasses&&this.element.addClass("ui-droppable")},destroy:function(){for(var a=d.ui.ddmanager.droppables[this.options.scope],b=0;b<a.length;b++)a[b]==this&&a.splice(b,1);this.element.removeClass("ui-droppable ui-droppable-disabled").removeData("droppable").unbind(".droppable");return this},_setOption:function(a,b){if(a=="accept")this.accept=d.isFunction(b)?b:function(c){return c.is(b)};d.Widget.prototype._setOption.apply(this,arguments)},_activate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&
|
133 |
-
this.element.addClass(this.options.activeClass);b&&this._trigger("activate",a,this.ui(b))},_deactivate:function(a){var b=d.ui.ddmanager.current;this.options.activeClass&&this.element.removeClass(this.options.activeClass);b&&this._trigger("deactivate",a,this.ui(b))},_over:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.addClass(this.options.hoverClass);
|
134 |
-
this._trigger("over",a,this.ui(b))}},_out:function(a){var b=d.ui.ddmanager.current;if(!(!b||(b.currentItem||b.element)[0]==this.element[0]))if(this.accept.call(this.element[0],b.currentItem||b.element)){this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("out",a,this.ui(b))}},_drop:function(a,b){var c=b||d.ui.ddmanager.current;if(!c||(c.currentItem||c.element)[0]==this.element[0])return false;var e=false;this.element.find(":data(droppable)").not(".ui-draggable-dragging").each(function(){var g=
|
135 |
-
d.data(this,"droppable");if(g.options.greedy&&!g.options.disabled&&g.options.scope==c.options.scope&&g.accept.call(g.element[0],c.currentItem||c.element)&&d.ui.intersect(c,d.extend(g,{offset:g.element.offset()}),g.options.tolerance)){e=true;return false}});if(e)return false;if(this.accept.call(this.element[0],c.currentItem||c.element)){this.options.activeClass&&this.element.removeClass(this.options.activeClass);this.options.hoverClass&&this.element.removeClass(this.options.hoverClass);this._trigger("drop",
|
136 |
-
a,this.ui(c));return this.element}return false},ui:function(a){return{draggable:a.currentItem||a.element,helper:a.helper,position:a.position,offset:a.positionAbs}}});d.extend(d.ui.droppable,{version:"1.8.9"});d.ui.intersect=function(a,b,c){if(!b.offset)return false;var e=(a.positionAbs||a.position.absolute).left,g=e+a.helperProportions.width,f=(a.positionAbs||a.position.absolute).top,h=f+a.helperProportions.height,i=b.offset.left,k=i+b.proportions.width,j=b.offset.top,l=j+b.proportions.height;
|
137 |
-
switch(c){case "fit":return i<=e&&g<=k&&j<=f&&h<=l;case "intersect":return i<e+a.helperProportions.width/2&&g-a.helperProportions.width/2<k&&j<f+a.helperProportions.height/2&&h-a.helperProportions.height/2<l;case "pointer":return d.ui.isOver((a.positionAbs||a.position.absolute).top+(a.clickOffset||a.offset.click).top,(a.positionAbs||a.position.absolute).left+(a.clickOffset||a.offset.click).left,j,i,b.proportions.height,b.proportions.width);case "touch":return(f>=j&&f<=l||h>=j&&h<=l||f<j&&h>l)&&(e>=
|
138 |
-
i&&e<=k||g>=i&&g<=k||e<i&&g>k);default:return false}};d.ui.ddmanager={current:null,droppables:{"default":[]},prepareOffsets:function(a,b){var c=d.ui.ddmanager.droppables[a.options.scope]||[],e=b?b.type:null,g=(a.currentItem||a.element).find(":data(droppable)").andSelf(),f=0;a:for(;f<c.length;f++)if(!(c[f].options.disabled||a&&!c[f].accept.call(c[f].element[0],a.currentItem||a.element))){for(var h=0;h<g.length;h++)if(g[h]==c[f].element[0]){c[f].proportions.height=0;continue a}c[f].visible=c[f].element.css("display")!=
|
139 |
-
"none";if(c[f].visible){c[f].offset=c[f].element.offset();c[f].proportions={width:c[f].element[0].offsetWidth,height:c[f].element[0].offsetHeight};e=="mousedown"&&c[f]._activate.call(c[f],b)}}},drop:function(a,b){var c=false;d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(this.options){if(!this.options.disabled&&this.visible&&d.ui.intersect(a,this,this.options.tolerance))c=c||this._drop.call(this,b);if(!this.options.disabled&&this.visible&&this.accept.call(this.element[0],a.currentItem||
|
140 |
-
a.element)){this.isout=1;this.isover=0;this._deactivate.call(this,b)}}});return c},drag:function(a,b){a.options.refreshPositions&&d.ui.ddmanager.prepareOffsets(a,b);d.each(d.ui.ddmanager.droppables[a.options.scope]||[],function(){if(!(this.options.disabled||this.greedyChild||!this.visible)){var c=d.ui.intersect(a,this,this.options.tolerance);if(c=!c&&this.isover==1?"isout":c&&this.isover==0?"isover":null){var e;if(this.options.greedy){var g=this.element.parents(":data(droppable):eq(0)");if(g.length){e=
|
141 |
-
d.data(g[0],"droppable");e.greedyChild=c=="isover"?1:0}}if(e&&c=="isover"){e.isover=0;e.isout=1;e._out.call(e,b)}this[c]=1;this[c=="isout"?"isover":"isout"]=0;this[c=="isover"?"_over":"_out"].call(this,b);if(e&&c=="isout"){e.isout=0;e.isover=1;e._over.call(e,b)}}}})}}})(jQuery);
|
142 |
-
;/*
|
143 |
-
* jQuery UI Resizable 1.8.9
|
144 |
-
*
|
145 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
146 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
147 |
-
* http://jquery.org/license
|
148 |
-
*
|
149 |
-
* http://docs.jquery.com/UI/Resizables
|
150 |
-
*
|
151 |
-
* Depends:
|
152 |
-
* jquery.ui.core.js
|
153 |
-
* jquery.ui.mouse.js
|
154 |
-
* jquery.ui.widget.js
|
155 |
-
*/
|
156 |
-
(function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element,
|
157 |
-
_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),
|
158 |
-
top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=
|
159 |
-
this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",
|
160 |
-
nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class="ui-resizable-handle '+("ui-resizable-"+f)+'"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==
|
161 |
-
String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection();
|
162 |
-
this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){e(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};
|
163 |
-
if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),
|
164 |
-
d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=
|
165 |
-
this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:
|
166 |
-
this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",
|
167 |
-
b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;
|
168 |
-
f={width:c.size.width-(f?0:c.sizeDiff.width),height:c.size.height-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",
|
169 |
-
b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top=
|
170 |
-
a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=l(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=l(b.width)&&a.minWidth&&a.minWidth>b.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,
|
171 |
-
k=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=[c.css("borderTopWidth"),
|
172 |
-
c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],f=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)||0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(":hidden")||e(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=
|
173 |
-
this.element.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+
|
174 |
-
a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,
|
175 |
-
arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,
|
176 |
-
{version:"1.8.9"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,
|
177 |
-
function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=
|
178 |
-
(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css("position"))){c._revertToRelativePosition=true;k.css({position:"absolute",top:"auto",left:"auto"})}k.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=
|
179 |
-
false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-
|
180 |
-
a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",
|
181 |
-
b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top",
|
182 |
-
"Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,
|
183 |
-
f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=
|
184 |
-
a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+
|
185 |
-
a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&
|
186 |
-
e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",
|
187 |
-
height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=
|
188 |
-
d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery);
|
189 |
-
;/*
|
190 |
-
* jQuery UI Selectable 1.8.9
|
191 |
-
*
|
192 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
193 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
194 |
-
* http://jquery.org/license
|
195 |
-
*
|
196 |
-
* http://docs.jquery.com/UI/Selectables
|
197 |
-
*
|
198 |
-
* Depends:
|
199 |
-
* jquery.ui.core.js
|
200 |
-
* jquery.ui.mouse.js
|
201 |
-
* jquery.ui.widget.js
|
202 |
-
*/
|
203 |
-
(function(e){e.widget("ui.selectable",e.ui.mouse,{options:{appendTo:"body",autoRefresh:true,distance:0,filter:"*",tolerance:"touch"},_create:function(){var c=this;this.element.addClass("ui-selectable");this.dragged=false;var f;this.refresh=function(){f=e(c.options.filter,c.element[0]);f.each(function(){var d=e(this),b=d.offset();e.data(this,"selectable-item",{element:this,$element:d,left:b.left,top:b.top,right:b.left+d.outerWidth(),bottom:b.top+d.outerHeight(),startselected:false,selected:d.hasClass("ui-selected"),
|
204 |
-
selecting:d.hasClass("ui-selecting"),unselecting:d.hasClass("ui-unselecting")})})};this.refresh();this.selectees=f.addClass("ui-selectee");this._mouseInit();this.helper=e("<div class='ui-selectable-helper'></div>")},destroy:function(){this.selectees.removeClass("ui-selectee").removeData("selectable-item");this.element.removeClass("ui-selectable ui-selectable-disabled").removeData("selectable").unbind(".selectable");this._mouseDestroy();return this},_mouseStart:function(c){var f=this;this.opos=[c.pageX,
|
205 |
-
c.pageY];if(!this.options.disabled){var d=this.options;this.selectees=e(d.filter,this.element[0]);this._trigger("start",c);e(d.appendTo).append(this.helper);this.helper.css({left:c.clientX,top:c.clientY,width:0,height:0});d.autoRefresh&&this.refresh();this.selectees.filter(".ui-selected").each(function(){var b=e.data(this,"selectable-item");b.startselected=true;if(!c.metaKey){b.$element.removeClass("ui-selected");b.selected=false;b.$element.addClass("ui-unselecting");b.unselecting=true;f._trigger("unselecting",
|
206 |
-
c,{unselecting:b.element})}});e(c.target).parents().andSelf().each(function(){var b=e.data(this,"selectable-item");if(b){var g=!c.metaKey||!b.$element.hasClass("ui-selected");b.$element.removeClass(g?"ui-unselecting":"ui-selected").addClass(g?"ui-selecting":"ui-unselecting");b.unselecting=!g;b.selecting=g;(b.selected=g)?f._trigger("selecting",c,{selecting:b.element}):f._trigger("unselecting",c,{unselecting:b.element});return false}})}},_mouseDrag:function(c){var f=this;this.dragged=true;if(!this.options.disabled){var d=
|
207 |
-
this.options,b=this.opos[0],g=this.opos[1],h=c.pageX,i=c.pageY;if(b>h){var j=h;h=b;b=j}if(g>i){j=i;i=g;g=j}this.helper.css({left:b,top:g,width:h-b,height:i-g});this.selectees.each(function(){var a=e.data(this,"selectable-item");if(!(!a||a.element==f.element[0])){var k=false;if(d.tolerance=="touch")k=!(a.left>h||a.right<b||a.top>i||a.bottom<g);else if(d.tolerance=="fit")k=a.left>b&&a.right<h&&a.top>g&&a.bottom<i;if(k){if(a.selected){a.$element.removeClass("ui-selected");a.selected=false}if(a.unselecting){a.$element.removeClass("ui-unselecting");
|
208 |
-
a.unselecting=false}if(!a.selecting){a.$element.addClass("ui-selecting");a.selecting=true;f._trigger("selecting",c,{selecting:a.element})}}else{if(a.selecting)if(c.metaKey&&a.startselected){a.$element.removeClass("ui-selecting");a.selecting=false;a.$element.addClass("ui-selected");a.selected=true}else{a.$element.removeClass("ui-selecting");a.selecting=false;if(a.startselected){a.$element.addClass("ui-unselecting");a.unselecting=true}f._trigger("unselecting",c,{unselecting:a.element})}if(a.selected)if(!c.metaKey&&
|
209 |
-
!a.startselected){a.$element.removeClass("ui-selected");a.selected=false;a.$element.addClass("ui-unselecting");a.unselecting=true;f._trigger("unselecting",c,{unselecting:a.element})}}}});return false}},_mouseStop:function(c){var f=this;this.dragged=false;e(".ui-unselecting",this.element[0]).each(function(){var d=e.data(this,"selectable-item");d.$element.removeClass("ui-unselecting");d.unselecting=false;d.startselected=false;f._trigger("unselected",c,{unselected:d.element})});e(".ui-selecting",this.element[0]).each(function(){var d=
|
210 |
-
e.data(this,"selectable-item");d.$element.removeClass("ui-selecting").addClass("ui-selected");d.selecting=false;d.selected=true;d.startselected=true;f._trigger("selected",c,{selected:d.element})});this._trigger("stop",c);this.helper.remove();return false}});e.extend(e.ui.selectable,{version:"1.8.9"})})(jQuery);
|
211 |
-
;/*
|
212 |
-
* jQuery UI Sortable 1.8.9
|
213 |
-
*
|
214 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
215 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
216 |
-
* http://jquery.org/license
|
217 |
-
*
|
218 |
-
* http://docs.jquery.com/UI/Sortables
|
219 |
-
*
|
220 |
-
* Depends:
|
221 |
-
* jquery.ui.core.js
|
222 |
-
* jquery.ui.mouse.js
|
223 |
-
* jquery.ui.widget.js
|
224 |
-
*/
|
225 |
-
(function(d){d.widget("ui.sortable",d.ui.mouse,{widgetEventPrefix:"sort",options:{appendTo:"parent",axis:false,connectWith:false,containment:false,cursor:"auto",cursorAt:false,dropOnEmpty:true,forcePlaceholderSize:false,forceHelperSize:false,grid:false,handle:false,helper:"original",items:"> *",opacity:false,placeholder:false,revert:false,scroll:true,scrollSensitivity:20,scrollSpeed:20,scope:"default",tolerance:"intersect",zIndex:1E3},_create:function(){this.containerCache={};this.element.addClass("ui-sortable");
|
226 |
-
this.refresh();this.floating=this.items.length?/left|right/.test(this.items[0].item.css("float")):false;this.offset=this.element.offset();this._mouseInit()},destroy:function(){this.element.removeClass("ui-sortable ui-sortable-disabled").removeData("sortable").unbind(".sortable");this._mouseDestroy();for(var a=this.items.length-1;a>=0;a--)this.items[a].item.removeData("sortable-item");return this},_setOption:function(a,b){if(a==="disabled"){this.options[a]=b;this.widget()[b?"addClass":"removeClass"]("ui-sortable-disabled")}else d.Widget.prototype._setOption.apply(this,
|
227 |
-
arguments)},_mouseCapture:function(a,b){if(this.reverting)return false;if(this.options.disabled||this.options.type=="static")return false;this._refreshItems(a);var c=null,e=this;d(a.target).parents().each(function(){if(d.data(this,"sortable-item")==e){c=d(this);return false}});if(d.data(a.target,"sortable-item")==e)c=d(a.target);if(!c)return false;if(this.options.handle&&!b){var f=false;d(this.options.handle,c).find("*").andSelf().each(function(){if(this==a.target)f=true});if(!f)return false}this.currentItem=
|
228 |
-
c;this._removeCurrentsFromItems();return true},_mouseStart:function(a,b,c){b=this.options;var e=this;this.currentContainer=this;this.refreshPositions();this.helper=this._createHelper(a);this._cacheHelperProportions();this._cacheMargins();this.scrollParent=this.helper.scrollParent();this.offset=this.currentItem.offset();this.offset={top:this.offset.top-this.margins.top,left:this.offset.left-this.margins.left};this.helper.css("position","absolute");this.cssPosition=this.helper.css("position");d.extend(this.offset,
|
229 |
-
{click:{left:a.pageX-this.offset.left,top:a.pageY-this.offset.top},parent:this._getParentOffset(),relative:this._getRelativeOffset()});this.originalPosition=this._generatePosition(a);this.originalPageX=a.pageX;this.originalPageY=a.pageY;b.cursorAt&&this._adjustOffsetFromHelper(b.cursorAt);this.domPosition={prev:this.currentItem.prev()[0],parent:this.currentItem.parent()[0]};this.helper[0]!=this.currentItem[0]&&this.currentItem.hide();this._createPlaceholder();b.containment&&this._setContainment();
|
230 |
-
if(b.cursor){if(d("body").css("cursor"))this._storedCursor=d("body").css("cursor");d("body").css("cursor",b.cursor)}if(b.opacity){if(this.helper.css("opacity"))this._storedOpacity=this.helper.css("opacity");this.helper.css("opacity",b.opacity)}if(b.zIndex){if(this.helper.css("zIndex"))this._storedZIndex=this.helper.css("zIndex");this.helper.css("zIndex",b.zIndex)}if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML")this.overflowOffset=this.scrollParent.offset();this._trigger("start",
|
231 |
-
a,this._uiHash());this._preserveHelperProportions||this._cacheHelperProportions();if(!c)for(c=this.containers.length-1;c>=0;c--)this.containers[c]._trigger("activate",a,e._uiHash(this));if(d.ui.ddmanager)d.ui.ddmanager.current=this;d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a);this.dragging=true;this.helper.addClass("ui-sortable-helper");this._mouseDrag(a);return true},_mouseDrag:function(a){this.position=this._generatePosition(a);this.positionAbs=this._convertPositionTo("absolute");
|
232 |
-
if(!this.lastPositionAbs)this.lastPositionAbs=this.positionAbs;if(this.options.scroll){var b=this.options,c=false;if(this.scrollParent[0]!=document&&this.scrollParent[0].tagName!="HTML"){if(this.overflowOffset.top+this.scrollParent[0].offsetHeight-a.pageY<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop+b.scrollSpeed;else if(a.pageY-this.overflowOffset.top<b.scrollSensitivity)this.scrollParent[0].scrollTop=c=this.scrollParent[0].scrollTop-b.scrollSpeed;if(this.overflowOffset.left+
|
233 |
-
this.scrollParent[0].offsetWidth-a.pageX<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft+b.scrollSpeed;else if(a.pageX-this.overflowOffset.left<b.scrollSensitivity)this.scrollParent[0].scrollLeft=c=this.scrollParent[0].scrollLeft-b.scrollSpeed}else{if(a.pageY-d(document).scrollTop()<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()-b.scrollSpeed);else if(d(window).height()-(a.pageY-d(document).scrollTop())<b.scrollSensitivity)c=d(document).scrollTop(d(document).scrollTop()+
|
234 |
-
b.scrollSpeed);if(a.pageX-d(document).scrollLeft()<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()-b.scrollSpeed);else if(d(window).width()-(a.pageX-d(document).scrollLeft())<b.scrollSensitivity)c=d(document).scrollLeft(d(document).scrollLeft()+b.scrollSpeed)}c!==false&&d.ui.ddmanager&&!b.dropBehaviour&&d.ui.ddmanager.prepareOffsets(this,a)}this.positionAbs=this._convertPositionTo("absolute");if(!this.options.axis||this.options.axis!="y")this.helper[0].style.left=this.position.left+
|
235 |
-
"px";if(!this.options.axis||this.options.axis!="x")this.helper[0].style.top=this.position.top+"px";for(b=this.items.length-1;b>=0;b--){c=this.items[b];var e=c.item[0],f=this._intersectsWithPointer(c);if(f)if(e!=this.currentItem[0]&&this.placeholder[f==1?"next":"prev"]()[0]!=e&&!d.ui.contains(this.placeholder[0],e)&&(this.options.type=="semi-dynamic"?!d.ui.contains(this.element[0],e):true)){this.direction=f==1?"down":"up";if(this.options.tolerance=="pointer"||this._intersectsWithSides(c))this._rearrange(a,
|
236 |
-
c);else break;this._trigger("change",a,this._uiHash());break}}this._contactContainers(a);d.ui.ddmanager&&d.ui.ddmanager.drag(this,a);this._trigger("sort",a,this._uiHash());this.lastPositionAbs=this.positionAbs;return false},_mouseStop:function(a,b){if(a){d.ui.ddmanager&&!this.options.dropBehaviour&&d.ui.ddmanager.drop(this,a);if(this.options.revert){var c=this;b=c.placeholder.offset();c.reverting=true;d(this.helper).animate({left:b.left-this.offset.parent.left-c.margins.left+(this.offsetParent[0]==
|
237 |
-
document.body?0:this.offsetParent[0].scrollLeft),top:b.top-this.offset.parent.top-c.margins.top+(this.offsetParent[0]==document.body?0:this.offsetParent[0].scrollTop)},parseInt(this.options.revert,10)||500,function(){c._clear(a)})}else this._clear(a,b);return false}},cancel:function(){var a=this;if(this.dragging){this._mouseUp({target:null});this.options.helper=="original"?this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper"):this.currentItem.show();for(var b=this.containers.length-
|
238 |
-
1;b>=0;b--){this.containers[b]._trigger("deactivate",null,a._uiHash(this));if(this.containers[b].containerCache.over){this.containers[b]._trigger("out",null,a._uiHash(this));this.containers[b].containerCache.over=0}}}if(this.placeholder){this.placeholder[0].parentNode&&this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.options.helper!="original"&&this.helper&&this.helper[0].parentNode&&this.helper.remove();d.extend(this,{helper:null,dragging:false,reverting:false,_noFinalSort:null});
|
239 |
-
this.domPosition.prev?d(this.domPosition.prev).after(this.currentItem):d(this.domPosition.parent).prepend(this.currentItem)}return this},serialize:function(a){var b=this._getItemsAsjQuery(a&&a.connected),c=[];a=a||{};d(b).each(function(){var e=(d(a.item||this).attr(a.attribute||"id")||"").match(a.expression||/(.+)[-=_](.+)/);if(e)c.push((a.key||e[1]+"[]")+"="+(a.key&&a.expression?e[1]:e[2]))});!c.length&&a.key&&c.push(a.key+"=");return c.join("&")},toArray:function(a){var b=this._getItemsAsjQuery(a&&
|
240 |
-
a.connected),c=[];a=a||{};b.each(function(){c.push(d(a.item||this).attr(a.attribute||"id")||"")});return c},_intersectsWith:function(a){var b=this.positionAbs.left,c=b+this.helperProportions.width,e=this.positionAbs.top,f=e+this.helperProportions.height,g=a.left,h=g+a.width,i=a.top,k=i+a.height,j=this.offset.click.top,l=this.offset.click.left;j=e+j>i&&e+j<k&&b+l>g&&b+l<h;return this.options.tolerance=="pointer"||this.options.forcePointerForContainers||this.options.tolerance!="pointer"&&this.helperProportions[this.floating?
|
241 |
-
"width":"height"]>a[this.floating?"width":"height"]?j:g<b+this.helperProportions.width/2&&c-this.helperProportions.width/2<h&&i<e+this.helperProportions.height/2&&f-this.helperProportions.height/2<k},_intersectsWithPointer:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left,a.width);b=b&&a;a=this._getDragVerticalDirection();var c=this._getDragHorizontalDirection();if(!b)return false;return this.floating?
|
242 |
-
c&&c=="right"||a=="down"?2:1:a&&(a=="down"?2:1)},_intersectsWithSides:function(a){var b=d.ui.isOverAxis(this.positionAbs.top+this.offset.click.top,a.top+a.height/2,a.height);a=d.ui.isOverAxis(this.positionAbs.left+this.offset.click.left,a.left+a.width/2,a.width);var c=this._getDragVerticalDirection(),e=this._getDragHorizontalDirection();return this.floating&&e?e=="right"&&a||e=="left"&&!a:c&&(c=="down"&&b||c=="up"&&!b)},_getDragVerticalDirection:function(){var a=this.positionAbs.top-this.lastPositionAbs.top;
|
243 |
-
return a!=0&&(a>0?"down":"up")},_getDragHorizontalDirection:function(){var a=this.positionAbs.left-this.lastPositionAbs.left;return a!=0&&(a>0?"right":"left")},refresh:function(a){this._refreshItems(a);this.refreshPositions();return this},_connectWith:function(){var a=this.options;return a.connectWith.constructor==String?[a.connectWith]:a.connectWith},_getItemsAsjQuery:function(a){var b=[],c=[],e=this._connectWith();if(e&&a)for(a=e.length-1;a>=0;a--)for(var f=d(e[a]),g=f.length-1;g>=0;g--){var h=
|
244 |
-
d.data(f[g],"sortable");if(h&&h!=this&&!h.options.disabled)c.push([d.isFunction(h.options.items)?h.options.items.call(h.element):d(h.options.items,h.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),h])}c.push([d.isFunction(this.options.items)?this.options.items.call(this.element,null,{options:this.options,item:this.currentItem}):d(this.options.items,this.element).not(".ui-sortable-helper").not(".ui-sortable-placeholder"),this]);for(a=c.length-1;a>=0;a--)c[a][0].each(function(){b.push(this)});
|
245 |
-
return d(b)},_removeCurrentsFromItems:function(){for(var a=this.currentItem.find(":data(sortable-item)"),b=0;b<this.items.length;b++)for(var c=0;c<a.length;c++)a[c]==this.items[b].item[0]&&this.items.splice(b,1)},_refreshItems:function(a){this.items=[];this.containers=[this];var b=this.items,c=[[d.isFunction(this.options.items)?this.options.items.call(this.element[0],a,{item:this.currentItem}):d(this.options.items,this.element),this]],e=this._connectWith();if(e)for(var f=e.length-1;f>=0;f--)for(var g=
|
246 |
-
d(e[f]),h=g.length-1;h>=0;h--){var i=d.data(g[h],"sortable");if(i&&i!=this&&!i.options.disabled){c.push([d.isFunction(i.options.items)?i.options.items.call(i.element[0],a,{item:this.currentItem}):d(i.options.items,i.element),i]);this.containers.push(i)}}for(f=c.length-1;f>=0;f--){a=c[f][1];e=c[f][0];h=0;for(g=e.length;h<g;h++){i=d(e[h]);i.data("sortable-item",a);b.push({item:i,instance:a,width:0,height:0,left:0,top:0})}}},refreshPositions:function(a){if(this.offsetParent&&this.helper)this.offset.parent=
|
247 |
-
this._getParentOffset();for(var b=this.items.length-1;b>=0;b--){var c=this.items[b],e=this.options.toleranceElement?d(this.options.toleranceElement,c.item):c.item;if(!a){c.width=e.outerWidth();c.height=e.outerHeight()}e=e.offset();c.left=e.left;c.top=e.top}if(this.options.custom&&this.options.custom.refreshContainers)this.options.custom.refreshContainers.call(this);else for(b=this.containers.length-1;b>=0;b--){e=this.containers[b].element.offset();this.containers[b].containerCache.left=e.left;this.containers[b].containerCache.top=
|
248 |
-
e.top;this.containers[b].containerCache.width=this.containers[b].element.outerWidth();this.containers[b].containerCache.height=this.containers[b].element.outerHeight()}return this},_createPlaceholder:function(a){var b=a||this,c=b.options;if(!c.placeholder||c.placeholder.constructor==String){var e=c.placeholder;c.placeholder={element:function(){var f=d(document.createElement(b.currentItem[0].nodeName)).addClass(e||b.currentItem[0].className+" ui-sortable-placeholder").removeClass("ui-sortable-helper")[0];
|
249 |
-
if(!e)f.style.visibility="hidden";return f},update:function(f,g){if(!(e&&!c.forcePlaceholderSize)){g.height()||g.height(b.currentItem.innerHeight()-parseInt(b.currentItem.css("paddingTop")||0,10)-parseInt(b.currentItem.css("paddingBottom")||0,10));g.width()||g.width(b.currentItem.innerWidth()-parseInt(b.currentItem.css("paddingLeft")||0,10)-parseInt(b.currentItem.css("paddingRight")||0,10))}}}}b.placeholder=d(c.placeholder.element.call(b.element,b.currentItem));b.currentItem.after(b.placeholder);
|
250 |
-
c.placeholder.update(b,b.placeholder)},_contactContainers:function(a){for(var b=null,c=null,e=this.containers.length-1;e>=0;e--)if(!d.ui.contains(this.currentItem[0],this.containers[e].element[0]))if(this._intersectsWith(this.containers[e].containerCache)){if(!(b&&d.ui.contains(this.containers[e].element[0],b.element[0]))){b=this.containers[e];c=e}}else if(this.containers[e].containerCache.over){this.containers[e]._trigger("out",a,this._uiHash(this));this.containers[e].containerCache.over=0}if(b)if(this.containers.length===
|
251 |
-
1){this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}else if(this.currentContainer!=this.containers[c]){b=1E4;e=null;for(var f=this.positionAbs[this.containers[c].floating?"left":"top"],g=this.items.length-1;g>=0;g--)if(d.ui.contains(this.containers[c].element[0],this.items[g].item[0])){var h=this.items[g][this.containers[c].floating?"left":"top"];if(Math.abs(h-f)<b){b=Math.abs(h-f);e=this.items[g]}}if(e||this.options.dropOnEmpty){this.currentContainer=
|
252 |
-
this.containers[c];e?this._rearrange(a,e,null,true):this._rearrange(a,null,this.containers[c].element,true);this._trigger("change",a,this._uiHash());this.containers[c]._trigger("change",a,this._uiHash(this));this.options.placeholder.update(this.currentContainer,this.placeholder);this.containers[c]._trigger("over",a,this._uiHash(this));this.containers[c].containerCache.over=1}}},_createHelper:function(a){var b=this.options;a=d.isFunction(b.helper)?d(b.helper.apply(this.element[0],[a,this.currentItem])):
|
253 |
-
b.helper=="clone"?this.currentItem.clone():this.currentItem;a.parents("body").length||d(b.appendTo!="parent"?b.appendTo:this.currentItem[0].parentNode)[0].appendChild(a[0]);if(a[0]==this.currentItem[0])this._storedCSS={width:this.currentItem[0].style.width,height:this.currentItem[0].style.height,position:this.currentItem.css("position"),top:this.currentItem.css("top"),left:this.currentItem.css("left")};if(a[0].style.width==""||b.forceHelperSize)a.width(this.currentItem.width());if(a[0].style.height==
|
254 |
-
""||b.forceHelperSize)a.height(this.currentItem.height());return a},_adjustOffsetFromHelper:function(a){if(typeof a=="string")a=a.split(" ");if(d.isArray(a))a={left:+a[0],top:+a[1]||0};if("left"in a)this.offset.click.left=a.left+this.margins.left;if("right"in a)this.offset.click.left=this.helperProportions.width-a.right+this.margins.left;if("top"in a)this.offset.click.top=a.top+this.margins.top;if("bottom"in a)this.offset.click.top=this.helperProportions.height-a.bottom+this.margins.top},_getParentOffset:function(){this.offsetParent=
|
255 |
-
this.helper.offsetParent();var a=this.offsetParent.offset();if(this.cssPosition=="absolute"&&this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0])){a.left+=this.scrollParent.scrollLeft();a.top+=this.scrollParent.scrollTop()}if(this.offsetParent[0]==document.body||this.offsetParent[0].tagName&&this.offsetParent[0].tagName.toLowerCase()=="html"&&d.browser.msie)a={top:0,left:0};return{top:a.top+(parseInt(this.offsetParent.css("borderTopWidth"),10)||0),left:a.left+(parseInt(this.offsetParent.css("borderLeftWidth"),
|
256 |
-
10)||0)}},_getRelativeOffset:function(){if(this.cssPosition=="relative"){var a=this.currentItem.position();return{top:a.top-(parseInt(this.helper.css("top"),10)||0)+this.scrollParent.scrollTop(),left:a.left-(parseInt(this.helper.css("left"),10)||0)+this.scrollParent.scrollLeft()}}else return{top:0,left:0}},_cacheMargins:function(){this.margins={left:parseInt(this.currentItem.css("marginLeft"),10)||0,top:parseInt(this.currentItem.css("marginTop"),10)||0}},_cacheHelperProportions:function(){this.helperProportions=
|
257 |
-
{width:this.helper.outerWidth(),height:this.helper.outerHeight()}},_setContainment:function(){var a=this.options;if(a.containment=="parent")a.containment=this.helper[0].parentNode;if(a.containment=="document"||a.containment=="window")this.containment=[0-this.offset.relative.left-this.offset.parent.left,0-this.offset.relative.top-this.offset.parent.top,d(a.containment=="document"?document:window).width()-this.helperProportions.width-this.margins.left,(d(a.containment=="document"?document:window).height()||
|
258 |
-
document.body.parentNode.scrollHeight)-this.helperProportions.height-this.margins.top];if(!/^(document|window|parent)$/.test(a.containment)){var b=d(a.containment)[0];a=d(a.containment).offset();var c=d(b).css("overflow")!="hidden";this.containment=[a.left+(parseInt(d(b).css("borderLeftWidth"),10)||0)+(parseInt(d(b).css("paddingLeft"),10)||0)-this.margins.left,a.top+(parseInt(d(b).css("borderTopWidth"),10)||0)+(parseInt(d(b).css("paddingTop"),10)||0)-this.margins.top,a.left+(c?Math.max(b.scrollWidth,
|
259 |
-
b.offsetWidth):b.offsetWidth)-(parseInt(d(b).css("borderLeftWidth"),10)||0)-(parseInt(d(b).css("paddingRight"),10)||0)-this.helperProportions.width-this.margins.left,a.top+(c?Math.max(b.scrollHeight,b.offsetHeight):b.offsetHeight)-(parseInt(d(b).css("borderTopWidth"),10)||0)-(parseInt(d(b).css("paddingBottom"),10)||0)-this.helperProportions.height-this.margins.top]}},_convertPositionTo:function(a,b){if(!b)b=this.position;a=a=="absolute"?1:-1;var c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=
|
260 |
-
document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);return{top:b.top+this.offset.relative.top*a+this.offset.parent.top*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop())*a),left:b.left+this.offset.relative.left*a+this.offset.parent.left*a-(d.browser.safari&&this.cssPosition=="fixed"?0:(this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():
|
261 |
-
e?0:c.scrollLeft())*a)}},_generatePosition:function(a){var b=this.options,c=this.cssPosition=="absolute"&&!(this.scrollParent[0]!=document&&d.ui.contains(this.scrollParent[0],this.offsetParent[0]))?this.offsetParent:this.scrollParent,e=/(html|body)/i.test(c[0].tagName);if(this.cssPosition=="relative"&&!(this.scrollParent[0]!=document&&this.scrollParent[0]!=this.offsetParent[0]))this.offset.relative=this._getRelativeOffset();var f=a.pageX,g=a.pageY;if(this.originalPosition){if(this.containment){if(a.pageX-
|
262 |
-
this.offset.click.left<this.containment[0])f=this.containment[0]+this.offset.click.left;if(a.pageY-this.offset.click.top<this.containment[1])g=this.containment[1]+this.offset.click.top;if(a.pageX-this.offset.click.left>this.containment[2])f=this.containment[2]+this.offset.click.left;if(a.pageY-this.offset.click.top>this.containment[3])g=this.containment[3]+this.offset.click.top}if(b.grid){g=this.originalPageY+Math.round((g-this.originalPageY)/b.grid[1])*b.grid[1];g=this.containment?!(g-this.offset.click.top<
|
263 |
-
this.containment[1]||g-this.offset.click.top>this.containment[3])?g:!(g-this.offset.click.top<this.containment[1])?g-b.grid[1]:g+b.grid[1]:g;f=this.originalPageX+Math.round((f-this.originalPageX)/b.grid[0])*b.grid[0];f=this.containment?!(f-this.offset.click.left<this.containment[0]||f-this.offset.click.left>this.containment[2])?f:!(f-this.offset.click.left<this.containment[0])?f-b.grid[0]:f+b.grid[0]:f}}return{top:g-this.offset.click.top-this.offset.relative.top-this.offset.parent.top+(d.browser.safari&&
|
264 |
-
this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollTop():e?0:c.scrollTop()),left:f-this.offset.click.left-this.offset.relative.left-this.offset.parent.left+(d.browser.safari&&this.cssPosition=="fixed"?0:this.cssPosition=="fixed"?-this.scrollParent.scrollLeft():e?0:c.scrollLeft())}},_rearrange:function(a,b,c,e){c?c[0].appendChild(this.placeholder[0]):b.item[0].parentNode.insertBefore(this.placeholder[0],this.direction=="down"?b.item[0]:b.item[0].nextSibling);this.counter=
|
265 |
-
this.counter?++this.counter:1;var f=this,g=this.counter;window.setTimeout(function(){g==f.counter&&f.refreshPositions(!e)},0)},_clear:function(a,b){this.reverting=false;var c=[];!this._noFinalSort&&this.currentItem[0].parentNode&&this.placeholder.before(this.currentItem);this._noFinalSort=null;if(this.helper[0]==this.currentItem[0]){for(var e in this._storedCSS)if(this._storedCSS[e]=="auto"||this._storedCSS[e]=="static")this._storedCSS[e]="";this.currentItem.css(this._storedCSS).removeClass("ui-sortable-helper")}else this.currentItem.show();
|
266 |
-
this.fromOutside&&!b&&c.push(function(f){this._trigger("receive",f,this._uiHash(this.fromOutside))});if((this.fromOutside||this.domPosition.prev!=this.currentItem.prev().not(".ui-sortable-helper")[0]||this.domPosition.parent!=this.currentItem.parent()[0])&&!b)c.push(function(f){this._trigger("update",f,this._uiHash())});if(!d.ui.contains(this.element[0],this.currentItem[0])){b||c.push(function(f){this._trigger("remove",f,this._uiHash())});for(e=this.containers.length-1;e>=0;e--)if(d.ui.contains(this.containers[e].element[0],
|
267 |
-
this.currentItem[0])&&!b){c.push(function(f){return function(g){f._trigger("receive",g,this._uiHash(this))}}.call(this,this.containers[e]));c.push(function(f){return function(g){f._trigger("update",g,this._uiHash(this))}}.call(this,this.containers[e]))}}for(e=this.containers.length-1;e>=0;e--){b||c.push(function(f){return function(g){f._trigger("deactivate",g,this._uiHash(this))}}.call(this,this.containers[e]));if(this.containers[e].containerCache.over){c.push(function(f){return function(g){f._trigger("out",
|
268 |
-
g,this._uiHash(this))}}.call(this,this.containers[e]));this.containers[e].containerCache.over=0}}this._storedCursor&&d("body").css("cursor",this._storedCursor);this._storedOpacity&&this.helper.css("opacity",this._storedOpacity);if(this._storedZIndex)this.helper.css("zIndex",this._storedZIndex=="auto"?"":this._storedZIndex);this.dragging=false;if(this.cancelHelperRemoval){if(!b){this._trigger("beforeStop",a,this._uiHash());for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}return false}b||
|
269 |
-
this._trigger("beforeStop",a,this._uiHash());this.placeholder[0].parentNode.removeChild(this.placeholder[0]);this.helper[0]!=this.currentItem[0]&&this.helper.remove();this.helper=null;if(!b){for(e=0;e<c.length;e++)c[e].call(this,a);this._trigger("stop",a,this._uiHash())}this.fromOutside=false;return true},_trigger:function(){d.Widget.prototype._trigger.apply(this,arguments)===false&&this.cancel()},_uiHash:function(a){var b=a||this;return{helper:b.helper,placeholder:b.placeholder||d([]),position:b.position,
|
270 |
-
originalPosition:b.originalPosition,offset:b.positionAbs,item:b.currentItem,sender:a?a.element:null}}});d.extend(d.ui.sortable,{version:"1.8.9"})})(jQuery);
|
271 |
-
;/*
|
272 |
-
* jQuery UI Accordion 1.8.9
|
273 |
-
*
|
274 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
275 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
276 |
-
* http://jquery.org/license
|
277 |
-
*
|
278 |
-
* http://docs.jquery.com/UI/Accordion
|
279 |
-
*
|
280 |
-
* Depends:
|
281 |
-
* jquery.ui.core.js
|
282 |
-
* jquery.ui.widget.js
|
283 |
-
*/
|
284 |
-
(function(c){c.widget("ui.accordion",{options:{active:0,animated:"slide",autoHeight:true,clearStyle:false,collapsible:false,event:"click",fillSpace:false,header:"> li > :first-child,> :not(li):even",icons:{header:"ui-icon-triangle-1-e",headerSelected:"ui-icon-triangle-1-s"},navigation:false,navigationFilter:function(){return this.href.toLowerCase()===location.href.toLowerCase()}},_create:function(){var a=this,b=a.options;a.running=0;a.element.addClass("ui-accordion ui-widget ui-helper-reset").children("li").addClass("ui-accordion-li-fix");
|
285 |
-
a.headers=a.element.find(b.header).addClass("ui-accordion-header ui-helper-reset ui-state-default ui-corner-all").bind("mouseenter.accordion",function(){b.disabled||c(this).addClass("ui-state-hover")}).bind("mouseleave.accordion",function(){b.disabled||c(this).removeClass("ui-state-hover")}).bind("focus.accordion",function(){b.disabled||c(this).addClass("ui-state-focus")}).bind("blur.accordion",function(){b.disabled||c(this).removeClass("ui-state-focus")});a.headers.next().addClass("ui-accordion-content ui-helper-reset ui-widget-content ui-corner-bottom");
|
286 |
-
if(b.navigation){var d=a.element.find("a").filter(b.navigationFilter).eq(0);if(d.length){var h=d.closest(".ui-accordion-header");a.active=h.length?h:d.closest(".ui-accordion-content").prev()}}a.active=a._findActive(a.active||b.active).addClass("ui-state-default ui-state-active").toggleClass("ui-corner-all").toggleClass("ui-corner-top");a.active.next().addClass("ui-accordion-content-active");a._createIcons();a.resize();a.element.attr("role","tablist");a.headers.attr("role","tab").bind("keydown.accordion",
|
287 |
-
function(f){return a._keydown(f)}).next().attr("role","tabpanel");a.headers.not(a.active||"").attr({"aria-expanded":"false",tabIndex:-1}).next().hide();a.active.length?a.active.attr({"aria-expanded":"true",tabIndex:0}):a.headers.eq(0).attr("tabIndex",0);c.browser.safari||a.headers.find("a").attr("tabIndex",-1);b.event&&a.headers.bind(b.event.split(" ").join(".accordion ")+".accordion",function(f){a._clickHandler.call(a,f,this);f.preventDefault()})},_createIcons:function(){var a=this.options;if(a.icons){c("<span></span>").addClass("ui-icon "+
|
288 |
-
a.icons.header).prependTo(this.headers);this.active.children(".ui-icon").toggleClass(a.icons.header).toggleClass(a.icons.headerSelected);this.element.addClass("ui-accordion-icons")}},_destroyIcons:function(){this.headers.children(".ui-icon").remove();this.element.removeClass("ui-accordion-icons")},destroy:function(){var a=this.options;this.element.removeClass("ui-accordion ui-widget ui-helper-reset").removeAttr("role");this.headers.unbind(".accordion").removeClass("ui-accordion-header ui-accordion-disabled ui-helper-reset ui-state-default ui-corner-all ui-state-active ui-state-disabled ui-corner-top").removeAttr("role").removeAttr("aria-expanded").removeAttr("tabIndex");
|
289 |
-
this.headers.find("a").removeAttr("tabIndex");this._destroyIcons();var b=this.headers.next().css("display","").removeAttr("role").removeClass("ui-helper-reset ui-widget-content ui-corner-bottom ui-accordion-content ui-accordion-content-active ui-accordion-disabled ui-state-disabled");if(a.autoHeight||a.fillHeight)b.css("height","");return c.Widget.prototype.destroy.call(this)},_setOption:function(a,b){c.Widget.prototype._setOption.apply(this,arguments);a=="active"&&this.activate(b);if(a=="icons"){this._destroyIcons();
|
290 |
-
b&&this._createIcons()}if(a=="disabled")this.headers.add(this.headers.next())[b?"addClass":"removeClass"]("ui-accordion-disabled ui-state-disabled")},_keydown:function(a){if(!(this.options.disabled||a.altKey||a.ctrlKey)){var b=c.ui.keyCode,d=this.headers.length,h=this.headers.index(a.target),f=false;switch(a.keyCode){case b.RIGHT:case b.DOWN:f=this.headers[(h+1)%d];break;case b.LEFT:case b.UP:f=this.headers[(h-1+d)%d];break;case b.SPACE:case b.ENTER:this._clickHandler({target:a.target},a.target);
|
291 |
-
a.preventDefault()}if(f){c(a.target).attr("tabIndex",-1);c(f).attr("tabIndex",0);f.focus();return false}return true}},resize:function(){var a=this.options,b;if(a.fillSpace){if(c.browser.msie){var d=this.element.parent().css("overflow");this.element.parent().css("overflow","hidden")}b=this.element.parent().height();c.browser.msie&&this.element.parent().css("overflow",d);this.headers.each(function(){b-=c(this).outerHeight(true)});this.headers.next().each(function(){c(this).height(Math.max(0,b-c(this).innerHeight()+
|
292 |
-
c(this).height()))}).css("overflow","auto")}else if(a.autoHeight){b=0;this.headers.next().each(function(){b=Math.max(b,c(this).height("").height())}).height(b)}return this},activate:function(a){this.options.active=a;a=this._findActive(a)[0];this._clickHandler({target:a},a);return this},_findActive:function(a){return a?typeof a==="number"?this.headers.filter(":eq("+a+")"):this.headers.not(this.headers.not(a)):a===false?c([]):this.headers.filter(":eq(0)")},_clickHandler:function(a,b){var d=this.options;
|
293 |
-
if(!d.disabled)if(a.target){a=c(a.currentTarget||b);b=a[0]===this.active[0];d.active=d.collapsible&&b?false:this.headers.index(a);if(!(this.running||!d.collapsible&&b)){var h=this.active;j=a.next();g=this.active.next();e={options:d,newHeader:b&&d.collapsible?c([]):a,oldHeader:this.active,newContent:b&&d.collapsible?c([]):j,oldContent:g};var f=this.headers.index(this.active[0])>this.headers.index(a[0]);this.active=b?c([]):a;this._toggle(j,g,e,b,f);h.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);
|
294 |
-
if(!b){a.removeClass("ui-state-default ui-corner-all").addClass("ui-state-active ui-corner-top").children(".ui-icon").removeClass(d.icons.header).addClass(d.icons.headerSelected);a.next().addClass("ui-accordion-content-active")}}}else if(d.collapsible){this.active.removeClass("ui-state-active ui-corner-top").addClass("ui-state-default ui-corner-all").children(".ui-icon").removeClass(d.icons.headerSelected).addClass(d.icons.header);this.active.next().addClass("ui-accordion-content-active");var g=this.active.next(),
|
295 |
-
e={options:d,newHeader:c([]),oldHeader:d.active,newContent:c([]),oldContent:g},j=this.active=c([]);this._toggle(j,g,e)}},_toggle:function(a,b,d,h,f){var g=this,e=g.options;g.toShow=a;g.toHide=b;g.data=d;var j=function(){if(g)return g._completed.apply(g,arguments)};g._trigger("changestart",null,g.data);g.running=b.size()===0?a.size():b.size();if(e.animated){d={};d=e.collapsible&&h?{toShow:c([]),toHide:b,complete:j,down:f,autoHeight:e.autoHeight||e.fillSpace}:{toShow:a,toHide:b,complete:j,down:f,autoHeight:e.autoHeight||
|
296 |
-
e.fillSpace};if(!e.proxied)e.proxied=e.animated;if(!e.proxiedDuration)e.proxiedDuration=e.duration;e.animated=c.isFunction(e.proxied)?e.proxied(d):e.proxied;e.duration=c.isFunction(e.proxiedDuration)?e.proxiedDuration(d):e.proxiedDuration;h=c.ui.accordion.animations;var i=e.duration,k=e.animated;if(k&&!h[k]&&!c.easing[k])k="slide";h[k]||(h[k]=function(l){this.slide(l,{easing:k,duration:i||700})});h[k](d)}else{if(e.collapsible&&h)a.toggle();else{b.hide();a.show()}j(true)}b.prev().attr({"aria-expanded":"false",
|
297 |
-
tabIndex:-1}).blur();a.prev().attr({"aria-expanded":"true",tabIndex:0}).focus()},_completed:function(a){this.running=a?0:--this.running;if(!this.running){this.options.clearStyle&&this.toShow.add(this.toHide).css({height:"",overflow:""});this.toHide.removeClass("ui-accordion-content-active");if(this.toHide.length)this.toHide.parent()[0].className=this.toHide.parent()[0].className;this._trigger("change",null,this.data)}}});c.extend(c.ui.accordion,{version:"1.8.9",animations:{slide:function(a,b){a=
|
298 |
-
c.extend({easing:"swing",duration:300},a,b);if(a.toHide.size())if(a.toShow.size()){var d=a.toShow.css("overflow"),h=0,f={},g={},e;b=a.toShow;e=b[0].style.width;b.width(parseInt(b.parent().width(),10)-parseInt(b.css("paddingLeft"),10)-parseInt(b.css("paddingRight"),10)-(parseInt(b.css("borderLeftWidth"),10)||0)-(parseInt(b.css("borderRightWidth"),10)||0));c.each(["height","paddingTop","paddingBottom"],function(j,i){g[i]="hide";j=(""+c.css(a.toShow[0],i)).match(/^([\d+-.]+)(.*)$/);f[i]={value:j[1],
|
299 |
-
unit:j[2]||"px"}});a.toShow.css({height:0,overflow:"hidden"}).show();a.toHide.filter(":hidden").each(a.complete).end().filter(":visible").animate(g,{step:function(j,i){if(i.prop=="height")h=i.end-i.start===0?0:(i.now-i.start)/(i.end-i.start);a.toShow[0].style[i.prop]=h*f[i.prop].value+f[i.prop].unit},duration:a.duration,easing:a.easing,complete:function(){a.autoHeight||a.toShow.css("height","");a.toShow.css({width:e,overflow:d});a.complete()}})}else a.toHide.animate({height:"hide",paddingTop:"hide",
|
300 |
-
paddingBottom:"hide"},a);else a.toShow.animate({height:"show",paddingTop:"show",paddingBottom:"show"},a)},bounceslide:function(a){this.slide(a,{easing:a.down?"easeOutBounce":"swing",duration:a.down?1E3:200})}}})})(jQuery);
|
301 |
-
;/*
|
302 |
-
* jQuery UI Autocomplete 1.8.9
|
303 |
-
*
|
304 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
305 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
306 |
-
* http://jquery.org/license
|
307 |
-
*
|
308 |
-
* http://docs.jquery.com/UI/Autocomplete
|
309 |
-
*
|
310 |
-
* Depends:
|
311 |
-
* jquery.ui.core.js
|
312 |
-
* jquery.ui.widget.js
|
313 |
-
* jquery.ui.position.js
|
314 |
-
*/
|
315 |
-
(function(d){d.widget("ui.autocomplete",{options:{appendTo:"body",delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null},pending:0,_create:function(){var a=this,b=this.element[0].ownerDocument,f;this.element.addClass("ui-autocomplete-input").attr("autocomplete","off").attr({role:"textbox","aria-autocomplete":"list","aria-haspopup":"true"}).bind("keydown.autocomplete",function(c){if(!(a.options.disabled||a.element.attr("readonly"))){f=false;var e=d.ui.keyCode;
|
316 |
-
switch(c.keyCode){case e.PAGE_UP:a._move("previousPage",c);break;case e.PAGE_DOWN:a._move("nextPage",c);break;case e.UP:a._move("previous",c);c.preventDefault();break;case e.DOWN:a._move("next",c);c.preventDefault();break;case e.ENTER:case e.NUMPAD_ENTER:if(a.menu.active){f=true;c.preventDefault()}case e.TAB:if(!a.menu.active)return;a.menu.select(c);break;case e.ESCAPE:a.element.val(a.term);a.close(c);break;default:clearTimeout(a.searching);a.searching=setTimeout(function(){if(a.term!=a.element.val()){a.selectedItem=
|
317 |
-
null;a.search(null,c)}},a.options.delay);break}}}).bind("keypress.autocomplete",function(c){if(f){f=false;c.preventDefault()}}).bind("focus.autocomplete",function(){if(!a.options.disabled){a.selectedItem=null;a.previous=a.element.val()}}).bind("blur.autocomplete",function(c){if(!a.options.disabled){clearTimeout(a.searching);a.closing=setTimeout(function(){a.close(c);a._change(c)},150)}});this._initSource();this.response=function(){return a._response.apply(a,arguments)};this.menu=d("<ul></ul>").addClass("ui-autocomplete").appendTo(d(this.options.appendTo||
|
318 |
-
"body",b)[0]).mousedown(function(c){var e=a.menu.element[0];d(c.target).closest(".ui-menu-item").length||setTimeout(function(){d(document).one("mousedown",function(g){g.target!==a.element[0]&&g.target!==e&&!d.ui.contains(e,g.target)&&a.close()})},1);setTimeout(function(){clearTimeout(a.closing)},13)}).menu({focus:function(c,e){e=e.item.data("item.autocomplete");false!==a._trigger("focus",c,{item:e})&&/^key/.test(c.originalEvent.type)&&a.element.val(e.value)},selected:function(c,e){var g=e.item.data("item.autocomplete"),
|
319 |
-
h=a.previous;if(a.element[0]!==b.activeElement){a.element.focus();a.previous=h;setTimeout(function(){a.previous=h;a.selectedItem=g},1)}false!==a._trigger("select",c,{item:g})&&a.element.val(g.value);a.term=a.element.val();a.close(c);a.selectedItem=g},blur:function(){a.menu.element.is(":visible")&&a.element.val()!==a.term&&a.element.val(a.term)}}).zIndex(this.element.zIndex()+1).css({top:0,left:0}).hide().data("menu");d.fn.bgiframe&&this.menu.element.bgiframe()},destroy:function(){this.element.removeClass("ui-autocomplete-input").removeAttr("autocomplete").removeAttr("role").removeAttr("aria-autocomplete").removeAttr("aria-haspopup");
|
320 |
-
this.menu.element.remove();d.Widget.prototype.destroy.call(this)},_setOption:function(a,b){d.Widget.prototype._setOption.apply(this,arguments);a==="source"&&this._initSource();if(a==="appendTo")this.menu.element.appendTo(d(b||"body",this.element[0].ownerDocument)[0]);a==="disabled"&&b&&this.xhr&&this.xhr.abort()},_initSource:function(){var a=this,b,f;if(d.isArray(this.options.source)){b=this.options.source;this.source=function(c,e){e(d.ui.autocomplete.filter(b,c.term))}}else if(typeof this.options.source===
|
321 |
-
"string"){f=this.options.source;this.source=function(c,e){a.xhr&&a.xhr.abort();a.xhr=d.ajax({url:f,data:c,dataType:"json",success:function(g,h,i){i===a.xhr&&e(g);a.xhr=null},error:function(g){g===a.xhr&&e([]);a.xhr=null}})}}else this.source=this.options.source},search:function(a,b){a=a!=null?a:this.element.val();this.term=this.element.val();if(a.length<this.options.minLength)return this.close(b);clearTimeout(this.closing);if(this._trigger("search",b)!==false)return this._search(a)},_search:function(a){this.pending++;
|
322 |
-
this.element.addClass("ui-autocomplete-loading");this.source({term:a},this.response)},_response:function(a){if(!this.options.disabled&&a&&a.length){a=this._normalize(a);this._suggest(a);this._trigger("open")}else this.close();this.pending--;this.pending||this.element.removeClass("ui-autocomplete-loading")},close:function(a){clearTimeout(this.closing);if(this.menu.element.is(":visible")){this.menu.element.hide();this.menu.deactivate();this._trigger("close",a)}},_change:function(a){this.previous!==
|
323 |
-
this.element.val()&&this._trigger("change",a,{item:this.selectedItem})},_normalize:function(a){if(a.length&&a[0].label&&a[0].value)return a;return d.map(a,function(b){if(typeof b==="string")return{label:b,value:b};return d.extend({label:b.label||b.value,value:b.value||b.label},b)})},_suggest:function(a){var b=this.menu.element.empty().zIndex(this.element.zIndex()+1);this._renderMenu(b,a);this.menu.deactivate();this.menu.refresh();b.show();this._resizeMenu();b.position(d.extend({of:this.element},this.options.position))},
|
324 |
-
_resizeMenu:function(){var a=this.menu.element;a.outerWidth(Math.max(a.width("").outerWidth(),this.element.outerWidth()))},_renderMenu:function(a,b){var f=this;d.each(b,function(c,e){f._renderItem(a,e)})},_renderItem:function(a,b){return d("<li></li>").data("item.autocomplete",b).append(d("<a></a>").text(b.label)).appendTo(a)},_move:function(a,b){if(this.menu.element.is(":visible"))if(this.menu.first()&&/^previous/.test(a)||this.menu.last()&&/^next/.test(a)){this.element.val(this.term);this.menu.deactivate()}else this.menu[a](b);
|
325 |
-
else this.search(null,b)},widget:function(){return this.menu.element}});d.extend(d.ui.autocomplete,{escapeRegex:function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")},filter:function(a,b){var f=new RegExp(d.ui.autocomplete.escapeRegex(b),"i");return d.grep(a,function(c){return f.test(c.label||c.value||c)})}})})(jQuery);
|
326 |
-
(function(d){d.widget("ui.menu",{_create:function(){var a=this;this.element.addClass("ui-menu ui-widget ui-widget-content ui-corner-all").attr({role:"listbox","aria-activedescendant":"ui-active-menuitem"}).click(function(b){if(d(b.target).closest(".ui-menu-item a").length){b.preventDefault();a.select(b)}});this.refresh()},refresh:function(){var a=this;this.element.children("li:not(.ui-menu-item):has(a)").addClass("ui-menu-item").attr("role","menuitem").children("a").addClass("ui-corner-all").attr("tabindex",
|
327 |
-
-1).mouseenter(function(b){a.activate(b,d(this).parent())}).mouseleave(function(){a.deactivate()})},activate:function(a,b){this.deactivate();if(this.hasScroll()){var f=b.offset().top-this.element.offset().top,c=this.element.attr("scrollTop"),e=this.element.height();if(f<0)this.element.attr("scrollTop",c+f);else f>=e&&this.element.attr("scrollTop",c+f-e+b.height())}this.active=b.eq(0).children("a").addClass("ui-state-hover").attr("id","ui-active-menuitem").end();this._trigger("focus",a,{item:b})},
|
328 |
-
deactivate:function(){if(this.active){this.active.children("a").removeClass("ui-state-hover").removeAttr("id");this._trigger("blur");this.active=null}},next:function(a){this.move("next",".ui-menu-item:first",a)},previous:function(a){this.move("prev",".ui-menu-item:last",a)},first:function(){return this.active&&!this.active.prevAll(".ui-menu-item").length},last:function(){return this.active&&!this.active.nextAll(".ui-menu-item").length},move:function(a,b,f){if(this.active){a=this.active[a+"All"](".ui-menu-item").eq(0);
|
329 |
-
a.length?this.activate(f,a):this.activate(f,this.element.children(b))}else this.activate(f,this.element.children(b))},nextPage:function(a){if(this.hasScroll())if(!this.active||this.last())this.activate(a,this.element.children(".ui-menu-item:first"));else{var b=this.active.offset().top,f=this.element.height(),c=this.element.children(".ui-menu-item").filter(function(){var e=d(this).offset().top-b-f+d(this).height();return e<10&&e>-10});c.length||(c=this.element.children(".ui-menu-item:last"));this.activate(a,
|
330 |
-
c)}else this.activate(a,this.element.children(".ui-menu-item").filter(!this.active||this.last()?":first":":last"))},previousPage:function(a){if(this.hasScroll())if(!this.active||this.first())this.activate(a,this.element.children(".ui-menu-item:last"));else{var b=this.active.offset().top,f=this.element.height();result=this.element.children(".ui-menu-item").filter(function(){var c=d(this).offset().top-b+f-d(this).height();return c<10&&c>-10});result.length||(result=this.element.children(".ui-menu-item:first"));
|
331 |
-
this.activate(a,result)}else this.activate(a,this.element.children(".ui-menu-item").filter(!this.active||this.first()?":last":":first"))},hasScroll:function(){return this.element.height()<this.element.attr("scrollHeight")},select:function(a){this._trigger("selected",a,{item:this.active})}})})(jQuery);
|
332 |
-
;/*
|
333 |
-
* jQuery UI Button 1.8.9
|
334 |
-
*
|
335 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
336 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
337 |
-
* http://jquery.org/license
|
338 |
-
*
|
339 |
-
* http://docs.jquery.com/UI/Button
|
340 |
-
*
|
341 |
-
* Depends:
|
342 |
-
* jquery.ui.core.js
|
343 |
-
* jquery.ui.widget.js
|
344 |
-
*/
|
345 |
-
(function(a){var g,i=function(b){a(":ui-button",b.target.form).each(function(){var c=a(this).data("button");setTimeout(function(){c.refresh()},1)})},h=function(b){var c=b.name,d=b.form,e=a([]);if(c)e=d?a(d).find("[name='"+c+"']"):a("[name='"+c+"']",b.ownerDocument).filter(function(){return!this.form});return e};a.widget("ui.button",{options:{disabled:null,text:true,label:null,icons:{primary:null,secondary:null}},_create:function(){this.element.closest("form").unbind("reset.button").bind("reset.button",
|
346 |
-
i);if(typeof this.options.disabled!=="boolean")this.options.disabled=this.element.attr("disabled");this._determineButtonType();this.hasTitle=!!this.buttonElement.attr("title");var b=this,c=this.options,d=this.type==="checkbox"||this.type==="radio",e="ui-state-hover"+(!d?" ui-state-active":"");if(c.label===null)c.label=this.buttonElement.html();if(this.element.is(":disabled"))c.disabled=true;this.buttonElement.addClass("ui-button ui-widget ui-state-default ui-corner-all").attr("role","button").bind("mouseenter.button",
|
347 |
-
function(){if(!c.disabled){a(this).addClass("ui-state-hover");this===g&&a(this).addClass("ui-state-active")}}).bind("mouseleave.button",function(){c.disabled||a(this).removeClass(e)}).bind("focus.button",function(){a(this).addClass("ui-state-focus")}).bind("blur.button",function(){a(this).removeClass("ui-state-focus")});d&&this.element.bind("change.button",function(){b.refresh()});if(this.type==="checkbox")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).toggleClass("ui-state-active");
|
348 |
-
b.buttonElement.attr("aria-pressed",b.element[0].checked)});else if(this.type==="radio")this.buttonElement.bind("click.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");b.buttonElement.attr("aria-pressed",true);var f=b.element[0];h(f).not(f).map(function(){return a(this).button("widget")[0]}).removeClass("ui-state-active").attr("aria-pressed",false)});else{this.buttonElement.bind("mousedown.button",function(){if(c.disabled)return false;a(this).addClass("ui-state-active");
|
349 |
-
g=this;a(document).one("mouseup",function(){g=null})}).bind("mouseup.button",function(){if(c.disabled)return false;a(this).removeClass("ui-state-active")}).bind("keydown.button",function(f){if(c.disabled)return false;if(f.keyCode==a.ui.keyCode.SPACE||f.keyCode==a.ui.keyCode.ENTER)a(this).addClass("ui-state-active")}).bind("keyup.button",function(){a(this).removeClass("ui-state-active")});this.buttonElement.is("a")&&this.buttonElement.keyup(function(f){f.keyCode===a.ui.keyCode.SPACE&&a(this).click()})}this._setOption("disabled",
|
350 |
-
c.disabled)},_determineButtonType:function(){this.type=this.element.is(":checkbox")?"checkbox":this.element.is(":radio")?"radio":this.element.is("input")?"input":"button";if(this.type==="checkbox"||this.type==="radio"){this.buttonElement=this.element.parents().last().find("label[for="+this.element.attr("id")+"]");this.element.addClass("ui-helper-hidden-accessible");var b=this.element.is(":checked");b&&this.buttonElement.addClass("ui-state-active");this.buttonElement.attr("aria-pressed",b)}else this.buttonElement=
|
351 |
-
this.element},widget:function(){return this.buttonElement},destroy:function(){this.element.removeClass("ui-helper-hidden-accessible");this.buttonElement.removeClass("ui-button ui-widget ui-state-default ui-corner-all ui-state-hover ui-state-active ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only").removeAttr("role").removeAttr("aria-pressed").html(this.buttonElement.find(".ui-button-text").html());this.hasTitle||
|
352 |
-
this.buttonElement.removeAttr("title");a.Widget.prototype.destroy.call(this)},_setOption:function(b,c){a.Widget.prototype._setOption.apply(this,arguments);if(b==="disabled")c?this.element.attr("disabled",true):this.element.removeAttr("disabled");this._resetButton()},refresh:function(){var b=this.element.is(":disabled");b!==this.options.disabled&&this._setOption("disabled",b);if(this.type==="radio")h(this.element[0]).each(function(){a(this).is(":checked")?a(this).button("widget").addClass("ui-state-active").attr("aria-pressed",
|
353 |
-
true):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed",false)});else if(this.type==="checkbox")this.element.is(":checked")?this.buttonElement.addClass("ui-state-active").attr("aria-pressed",true):this.buttonElement.removeClass("ui-state-active").attr("aria-pressed",false)},_resetButton:function(){if(this.type==="input")this.options.label&&this.element.val(this.options.label);else{var b=this.buttonElement.removeClass("ui-button-icons-only ui-button-icon-only ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary ui-button-text-only"),
|
354 |
-
c=a("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary;if(d.primary||d.secondary){b.addClass("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary"));d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>");d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>");if(!this.options.text){b.addClass(e?"ui-button-icons-only":"ui-button-icon-only").removeClass("ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary");
|
355 |
-
this.hasTitle||b.attr("title",c)}}else b.addClass("ui-button-text-only")}}});a.widget("ui.buttonset",{options:{items:":button, :submit, :reset, :checkbox, :radio, a, :data(button)"},_create:function(){this.element.addClass("ui-buttonset")},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(this.options.items).filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end()},
|
356 |
-
destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");a.Widget.prototype.destroy.call(this)}})})(jQuery);
|
357 |
-
;/*
|
358 |
-
* jQuery UI Dialog 1.8.9
|
359 |
-
*
|
360 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
361 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
362 |
-
* http://jquery.org/license
|
363 |
-
*
|
364 |
-
* http://docs.jquery.com/UI/Dialog
|
365 |
-
*
|
366 |
-
* Depends:
|
367 |
-
* jquery.ui.core.js
|
368 |
-
* jquery.ui.widget.js
|
369 |
-
* jquery.ui.button.js
|
370 |
-
* jquery.ui.draggable.js
|
371 |
-
* jquery.ui.mouse.js
|
372 |
-
* jquery.ui.position.js
|
373 |
-
* jquery.ui.resizable.js
|
374 |
-
*/
|
375 |
-
(function(c,j){var k={buttons:true,height:true,maxHeight:true,maxWidth:true,minHeight:true,minWidth:true,width:true},l={maxHeight:true,maxWidth:true,minHeight:true,minWidth:true};c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&
|
376 |
-
c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||" ",e=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",
|
377 |
-
-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog","aria-labelledby":e}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var f=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role",
|
378 |
-
"button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);return false}).appendTo(f);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id",e).html(d).prependTo(f);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=
|
379 |
-
b.beforeclose;f.find("*").add(f).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");a.uiDialog.remove();a.originalTitle&&
|
380 |
-
a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d,e;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==b.uiDialog[0]){e=c(this).css("z-index");
|
381 |
-
isNaN(e)||(d=Math.max(d,e))}});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,e=d.options;if(e.modal&&!a||!e.stack&&!e.modal)return d._trigger("focus",b);if(e.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=e.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};c.ui.dialog.maxZ+=1;d.uiDialog.css("z-index",c.ui.dialog.maxZ);
|
382 |
-
d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;a._size();a._position(b.position);d.show(b.show);a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(e){if(e.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),f=g.filter(":first");g=g.filter(":last");if(e.target===g[0]&&!e.shiftKey){f.focus(1);return false}else if(e.target===f[0]&&e.shiftKey){g.focus(1);return false}}});
|
383 |
-
c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,e=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("<div></div>").addClass("ui-dialog-buttonset").appendTo(e);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,function(){return!(d=true)});if(d){c.each(a,function(f,
|
384 |
-
h){h=c.isFunction(h)?{click:h,text:f}:h;f=c('<button type="button"></button>').attr(h,true).unbind("click").click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.fn.button&&f.button()});e.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(f){return{position:f.position,offset:f.offset}}var b=this,d=b.options,e=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(f,h){g=
|
385 |
-
d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",f,a(h))},drag:function(f,h){b._trigger("drag",f,a(h))},stop:function(f,h){d.position=[h.position.left-e.scrollLeft(),h.position.top-e.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);b._trigger("dragStop",f,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(f){return{originalPosition:f.originalPosition,originalSize:f.originalSize,
|
386 |
-
position:f.position,size:f.size}}a=a===j?this.options.resizable:a;var d=this,e=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:e.maxWidth,maxHeight:e.maxHeight,minWidth:e.minWidth,minHeight:d._minHeight(),handles:a,start:function(f,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",f,b(h))},resize:function(f,h){d._trigger("resize",f,b(h))},stop:function(f,
|
387 |
-
h){c(this).removeClass("ui-dialog-resizing");e.height=c(this).height();e.width=c(this).width();d._trigger("resizeStop",f,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,a.height)},_position:function(a){var b=[],d=[0,0],e;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):[a[0],a[1]];if(b.length===
|
388 |
-
1)b[1]=b[0];c.each(["left","top"],function(g,f){if(+b[g]===b[g]){d[g]=b[g];b[g]=f}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(e=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(c.extend({of:window},a));e||this.uiDialog.hide()},_setOptions:function(a){var b=this,d={},e=false;c.each(a,function(g,f){b._setOption(g,f);if(g in k)e=true;if(g in
|
389 |
-
l)d[g]=f});e&&this._size();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option",d)},_setOption:function(a,b){var d=this,e=d.uiDialog;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":e.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?e.addClass("ui-dialog-disabled"):e.removeClass("ui-dialog-disabled");
|
390 |
-
break;case "draggable":var g=e.is(":data(draggable)");g&&!b&&e.draggable("destroy");!g&&b&&d._makeDraggable();break;case "position":d._position(b);break;case "resizable":(g=e.is(":data(resizable)"))&&!b&&e.resizable("destroy");g&&typeof b==="string"&&e.resizable("option","handles",b);!g&&b!==false&&d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||" "));break}c.Widget.prototype._setOption.apply(d,arguments)},_size:function(){var a=this.options,b,d,e=
|
391 |
-
this.uiDialog.is(":visible");this.element.show().css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();d=Math.max(0,a.minHeight-b);if(a.height==="auto")if(c.support.minHeight)this.element.css({minHeight:d,height:"auto"});else{this.uiDialog.show();a=this.element.css("height","auto").height();e||this.uiDialog.hide();this.element.height(Math.max(a,d))}else this.element.height(Math.max(a.height-b,0));this.uiDialog.is(":data(resizable)")&&
|
392 |
-
this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.9",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),function(a){return a+".dialog-overlay"}).join(" "),create:function(a){if(this.instances.length===
|
393 |
-
0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=(this.oldInstances.pop()||c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),
|
394 |
-
height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){var b=c.inArray(a,this.instances);b!=-1&&this.oldInstances.push(this.instances.splice(b,1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var d=0;c.each(this.instances,function(){d=Math.max(d,this.css("z-index"))});this.maxZ=d},height:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);
|
395 |
-
b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<b?c(window).width()+"px":a+"px"}else return c(document).width()+"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,
|
396 |
-
function(){a=a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);
|
397 |
-
;/*
|
398 |
-
* jQuery UI Slider 1.8.9
|
399 |
-
*
|
400 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
401 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
402 |
-
* http://jquery.org/license
|
403 |
-
*
|
404 |
-
* http://docs.jquery.com/UI/Slider
|
405 |
-
*
|
406 |
-
* Depends:
|
407 |
-
* jquery.ui.core.js
|
408 |
-
* jquery.ui.mouse.js
|
409 |
-
* jquery.ui.widget.js
|
410 |
-
*/
|
411 |
-
(function(d){d.widget("ui.slider",d.ui.mouse,{widgetEventPrefix:"slide",options:{animate:false,distance:0,max:100,min:0,orientation:"horizontal",range:false,step:1,value:0,values:null},_create:function(){var b=this,a=this.options;this._mouseSliding=this._keySliding=false;this._animateOff=true;this._handleIndex=null;this._detectOrientation();this._mouseInit();this.element.addClass("ui-slider ui-slider-"+this.orientation+" ui-widget ui-widget-content ui-corner-all");a.disabled&&this.element.addClass("ui-slider-disabled ui-disabled");
|
412 |
-
this.range=d([]);if(a.range){if(a.range===true){this.range=d("<div></div>");if(!a.values)a.values=[this._valueMin(),this._valueMin()];if(a.values.length&&a.values.length!==2)a.values=[a.values[0],a.values[0]]}else this.range=d("<div></div>");this.range.appendTo(this.element).addClass("ui-slider-range");if(a.range==="min"||a.range==="max")this.range.addClass("ui-slider-range-"+a.range);this.range.addClass("ui-widget-header")}d(".ui-slider-handle",this.element).length===0&&d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");
|
413 |
-
if(a.values&&a.values.length)for(;d(".ui-slider-handle",this.element).length<a.values.length;)d("<a href='#'></a>").appendTo(this.element).addClass("ui-slider-handle");this.handles=d(".ui-slider-handle",this.element).addClass("ui-state-default ui-corner-all");this.handle=this.handles.eq(0);this.handles.add(this.range).filter("a").click(function(c){c.preventDefault()}).hover(function(){a.disabled||d(this).addClass("ui-state-hover")},function(){d(this).removeClass("ui-state-hover")}).focus(function(){if(a.disabled)d(this).blur();
|
414 |
-
else{d(".ui-slider .ui-state-focus").removeClass("ui-state-focus");d(this).addClass("ui-state-focus")}}).blur(function(){d(this).removeClass("ui-state-focus")});this.handles.each(function(c){d(this).data("index.ui-slider-handle",c)});this.handles.keydown(function(c){var e=true,f=d(this).data("index.ui-slider-handle"),h,g,i;if(!b.options.disabled){switch(c.keyCode){case d.ui.keyCode.HOME:case d.ui.keyCode.END:case d.ui.keyCode.PAGE_UP:case d.ui.keyCode.PAGE_DOWN:case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:e=
|
415 |
-
false;if(!b._keySliding){b._keySliding=true;d(this).addClass("ui-state-active");h=b._start(c,f);if(h===false)return}break}i=b.options.step;h=b.options.values&&b.options.values.length?(g=b.values(f)):(g=b.value());switch(c.keyCode){case d.ui.keyCode.HOME:g=b._valueMin();break;case d.ui.keyCode.END:g=b._valueMax();break;case d.ui.keyCode.PAGE_UP:g=b._trimAlignValue(h+(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.PAGE_DOWN:g=b._trimAlignValue(h-(b._valueMax()-b._valueMin())/5);break;case d.ui.keyCode.UP:case d.ui.keyCode.RIGHT:if(h===
|
416 |
-
b._valueMax())return;g=b._trimAlignValue(h+i);break;case d.ui.keyCode.DOWN:case d.ui.keyCode.LEFT:if(h===b._valueMin())return;g=b._trimAlignValue(h-i);break}b._slide(c,f,g);return e}}).keyup(function(c){var e=d(this).data("index.ui-slider-handle");if(b._keySliding){b._keySliding=false;b._stop(c,e);b._change(c,e);d(this).removeClass("ui-state-active")}});this._refreshValue();this._animateOff=false},destroy:function(){this.handles.remove();this.range.remove();this.element.removeClass("ui-slider ui-slider-horizontal ui-slider-vertical ui-slider-disabled ui-widget ui-widget-content ui-corner-all").removeData("slider").unbind(".slider");
|
417 |
-
this._mouseDestroy();return this},_mouseCapture:function(b){var a=this.options,c,e,f,h,g;if(a.disabled)return false;this.elementSize={width:this.element.outerWidth(),height:this.element.outerHeight()};this.elementOffset=this.element.offset();c=this._normValueFromMouse({x:b.pageX,y:b.pageY});e=this._valueMax()-this._valueMin()+1;h=this;this.handles.each(function(i){var j=Math.abs(c-h.values(i));if(e>j){e=j;f=d(this);g=i}});if(a.range===true&&this.values(1)===a.min){g+=1;f=d(this.handles[g])}if(this._start(b,
|
418 |
-
g)===false)return false;this._mouseSliding=true;h._handleIndex=g;f.addClass("ui-state-active").focus();a=f.offset();this._clickOffset=!d(b.target).parents().andSelf().is(".ui-slider-handle")?{left:0,top:0}:{left:b.pageX-a.left-f.width()/2,top:b.pageY-a.top-f.height()/2-(parseInt(f.css("borderTopWidth"),10)||0)-(parseInt(f.css("borderBottomWidth"),10)||0)+(parseInt(f.css("marginTop"),10)||0)};this.handles.hasClass("ui-state-hover")||this._slide(b,g,c);return this._animateOff=true},_mouseStart:function(){return true},
|
419 |
-
_mouseDrag:function(b){var a=this._normValueFromMouse({x:b.pageX,y:b.pageY});this._slide(b,this._handleIndex,a);return false},_mouseStop:function(b){this.handles.removeClass("ui-state-active");this._mouseSliding=false;this._stop(b,this._handleIndex);this._change(b,this._handleIndex);this._clickOffset=this._handleIndex=null;return this._animateOff=false},_detectOrientation:function(){this.orientation=this.options.orientation==="vertical"?"vertical":"horizontal"},_normValueFromMouse:function(b){var a;
|
420 |
-
if(this.orientation==="horizontal"){a=this.elementSize.width;b=b.x-this.elementOffset.left-(this._clickOffset?this._clickOffset.left:0)}else{a=this.elementSize.height;b=b.y-this.elementOffset.top-(this._clickOffset?this._clickOffset.top:0)}a=b/a;if(a>1)a=1;if(a<0)a=0;if(this.orientation==="vertical")a=1-a;b=this._valueMax()-this._valueMin();return this._trimAlignValue(this._valueMin()+a*b)},_start:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=
|
421 |
-
this.values(a);c.values=this.values()}return this._trigger("start",b,c)},_slide:function(b,a,c){var e;if(this.options.values&&this.options.values.length){e=this.values(a?0:1);if(this.options.values.length===2&&this.options.range===true&&(a===0&&c>e||a===1&&c<e))c=e;if(c!==this.values(a)){e=this.values();e[a]=c;b=this._trigger("slide",b,{handle:this.handles[a],value:c,values:e});this.values(a?0:1);b!==false&&this.values(a,c,true)}}else if(c!==this.value()){b=this._trigger("slide",b,{handle:this.handles[a],
|
422 |
-
value:c});b!==false&&this.value(c)}},_stop:function(b,a){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("stop",b,c)},_change:function(b,a){if(!this._keySliding&&!this._mouseSliding){var c={handle:this.handles[a],value:this.value()};if(this.options.values&&this.options.values.length){c.value=this.values(a);c.values=this.values()}this._trigger("change",b,c)}},value:function(b){if(arguments.length){this.options.value=
|
423 |
-
this._trimAlignValue(b);this._refreshValue();this._change(null,0)}return this._value()},values:function(b,a){var c,e,f;if(arguments.length>1){this.options.values[b]=this._trimAlignValue(a);this._refreshValue();this._change(null,b)}if(arguments.length)if(d.isArray(arguments[0])){c=this.options.values;e=arguments[0];for(f=0;f<c.length;f+=1){c[f]=this._trimAlignValue(e[f]);this._change(null,f)}this._refreshValue()}else return this.options.values&&this.options.values.length?this._values(b):this.value();
|
424 |
-
else return this._values()},_setOption:function(b,a){var c,e=0;if(d.isArray(this.options.values))e=this.options.values.length;d.Widget.prototype._setOption.apply(this,arguments);switch(b){case "disabled":if(a){this.handles.filter(".ui-state-focus").blur();this.handles.removeClass("ui-state-hover");this.handles.attr("disabled","disabled");this.element.addClass("ui-disabled")}else{this.handles.removeAttr("disabled");this.element.removeClass("ui-disabled")}break;case "orientation":this._detectOrientation();
|
425 |
-
this.element.removeClass("ui-slider-horizontal ui-slider-vertical").addClass("ui-slider-"+this.orientation);this._refreshValue();break;case "value":this._animateOff=true;this._refreshValue();this._change(null,0);this._animateOff=false;break;case "values":this._animateOff=true;this._refreshValue();for(c=0;c<e;c+=1)this._change(null,c);this._animateOff=false;break}},_value:function(){var b=this.options.value;return b=this._trimAlignValue(b)},_values:function(b){var a,c;if(arguments.length){a=this.options.values[b];
|
426 |
-
return a=this._trimAlignValue(a)}else{a=this.options.values.slice();for(c=0;c<a.length;c+=1)a[c]=this._trimAlignValue(a[c]);return a}},_trimAlignValue:function(b){if(b<=this._valueMin())return this._valueMin();if(b>=this._valueMax())return this._valueMax();var a=this.options.step>0?this.options.step:1,c=(b-this._valueMin())%a;alignValue=b-c;if(Math.abs(c)*2>=a)alignValue+=c>0?a:-a;return parseFloat(alignValue.toFixed(5))},_valueMin:function(){return this.options.min},_valueMax:function(){return this.options.max},
|
427 |
-
_refreshValue:function(){var b=this.options.range,a=this.options,c=this,e=!this._animateOff?a.animate:false,f,h={},g,i,j,l;if(this.options.values&&this.options.values.length)this.handles.each(function(k){f=(c.values(k)-c._valueMin())/(c._valueMax()-c._valueMin())*100;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";d(this).stop(1,1)[e?"animate":"css"](h,a.animate);if(c.options.range===true)if(c.orientation==="horizontal"){if(k===0)c.range.stop(1,1)[e?"animate":"css"]({left:f+"%"},a.animate);
|
428 |
-
if(k===1)c.range[e?"animate":"css"]({width:f-g+"%"},{queue:false,duration:a.animate})}else{if(k===0)c.range.stop(1,1)[e?"animate":"css"]({bottom:f+"%"},a.animate);if(k===1)c.range[e?"animate":"css"]({height:f-g+"%"},{queue:false,duration:a.animate})}g=f});else{i=this.value();j=this._valueMin();l=this._valueMax();f=l!==j?(i-j)/(l-j)*100:0;h[c.orientation==="horizontal"?"left":"bottom"]=f+"%";this.handle.stop(1,1)[e?"animate":"css"](h,a.animate);if(b==="min"&&this.orientation==="horizontal")this.range.stop(1,
|
429 |
-
1)[e?"animate":"css"]({width:f+"%"},a.animate);if(b==="max"&&this.orientation==="horizontal")this.range[e?"animate":"css"]({width:100-f+"%"},{queue:false,duration:a.animate});if(b==="min"&&this.orientation==="vertical")this.range.stop(1,1)[e?"animate":"css"]({height:f+"%"},a.animate);if(b==="max"&&this.orientation==="vertical")this.range[e?"animate":"css"]({height:100-f+"%"},{queue:false,duration:a.animate})}}});d.extend(d.ui.slider,{version:"1.8.9"})})(jQuery);
|
430 |
-
;/*
|
431 |
-
* jQuery UI Tabs 1.8.9
|
432 |
-
*
|
433 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
434 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
435 |
-
* http://jquery.org/license
|
436 |
-
*
|
437 |
-
* http://docs.jquery.com/UI/Tabs
|
438 |
-
*
|
439 |
-
* Depends:
|
440 |
-
* jquery.ui.core.js
|
441 |
-
* jquery.ui.widget.js
|
442 |
-
*/
|
443 |
-
(function(d,p){function u(){return++v}function w(){return++x}var v=0,x=0;d.widget("ui.tabs",{options:{add:null,ajaxOptions:null,cache:false,cookie:null,collapsible:false,disable:null,disabled:[],enable:null,event:"click",fx:null,idPrefix:"ui-tabs-",load:null,panelTemplate:"<div></div>",remove:null,select:null,show:null,spinner:"<em>Loading…</em>",tabTemplate:"<li><a href='#{href}'><span>#{label}</span></a></li>"},_create:function(){this._tabify(true)},_setOption:function(b,e){if(b=="selected")this.options.collapsible&&
|
444 |
-
e==this.options.selected||this.select(e);else{this.options[b]=e;this._tabify()}},_tabId:function(b){return b.title&&b.title.replace(/\s/g,"_").replace(/[^\w\u00c0-\uFFFF-]/g,"")||this.options.idPrefix+u()},_sanitizeSelector:function(b){return b.replace(/:/g,"\\:")},_cookie:function(){var b=this.cookie||(this.cookie=this.options.cookie.name||"ui-tabs-"+w());return d.cookie.apply(null,[b].concat(d.makeArray(arguments)))},_ui:function(b,e){return{tab:b,panel:e,index:this.anchors.index(b)}},_cleanup:function(){this.lis.filter(".ui-state-processing").removeClass("ui-state-processing").find("span:data(label.tabs)").each(function(){var b=
|
445 |
-
d(this);b.html(b.data("label.tabs")).removeData("label.tabs")})},_tabify:function(b){function e(g,f){g.css("display","");!d.support.opacity&&f.opacity&&g[0].style.removeAttribute("filter")}var a=this,c=this.options,h=/^#.+/;this.list=this.element.find("ol,ul").eq(0);this.lis=d(" > li:has(a[href])",this.list);this.anchors=this.lis.map(function(){return d("a",this)[0]});this.panels=d([]);this.anchors.each(function(g,f){var i=d(f).attr("href"),l=i.split("#")[0],q;if(l&&(l===location.toString().split("#")[0]||
|
446 |
-
(q=d("base")[0])&&l===q.href)){i=f.hash;f.href=i}if(h.test(i))a.panels=a.panels.add(a.element.find(a._sanitizeSelector(i)));else if(i&&i!=="#"){d.data(f,"href.tabs",i);d.data(f,"load.tabs",i.replace(/#.*$/,""));i=a._tabId(f);f.href="#"+i;f=a.element.find("#"+i);if(!f.length){f=d(c.panelTemplate).attr("id",i).addClass("ui-tabs-panel ui-widget-content ui-corner-bottom").insertAfter(a.panels[g-1]||a.list);f.data("destroy.tabs",true)}a.panels=a.panels.add(f)}else c.disabled.push(g)});if(b){this.element.addClass("ui-tabs ui-widget ui-widget-content ui-corner-all");
|
447 |
-
this.list.addClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.lis.addClass("ui-state-default ui-corner-top");this.panels.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom");if(c.selected===p){location.hash&&this.anchors.each(function(g,f){if(f.hash==location.hash){c.selected=g;return false}});if(typeof c.selected!=="number"&&c.cookie)c.selected=parseInt(a._cookie(),10);if(typeof c.selected!=="number"&&this.lis.filter(".ui-tabs-selected").length)c.selected=
|
448 |
-
this.lis.index(this.lis.filter(".ui-tabs-selected"));c.selected=c.selected||(this.lis.length?0:-1)}else if(c.selected===null)c.selected=-1;c.selected=c.selected>=0&&this.anchors[c.selected]||c.selected<0?c.selected:0;c.disabled=d.unique(c.disabled.concat(d.map(this.lis.filter(".ui-state-disabled"),function(g){return a.lis.index(g)}))).sort();d.inArray(c.selected,c.disabled)!=-1&&c.disabled.splice(d.inArray(c.selected,c.disabled),1);this.panels.addClass("ui-tabs-hide");this.lis.removeClass("ui-tabs-selected ui-state-active");
|
449 |
-
if(c.selected>=0&&this.anchors.length){a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash)).removeClass("ui-tabs-hide");this.lis.eq(c.selected).addClass("ui-tabs-selected ui-state-active");a.element.queue("tabs",function(){a._trigger("show",null,a._ui(a.anchors[c.selected],a.element.find(a._sanitizeSelector(a.anchors[c.selected].hash))[0]))});this.load(c.selected)}d(window).bind("unload",function(){a.lis.add(a.anchors).unbind(".tabs");a.lis=a.anchors=a.panels=null})}else c.selected=this.lis.index(this.lis.filter(".ui-tabs-selected"));
|
450 |
-
this.element[c.collapsible?"addClass":"removeClass"]("ui-tabs-collapsible");c.cookie&&this._cookie(c.selected,c.cookie);b=0;for(var j;j=this.lis[b];b++)d(j)[d.inArray(b,c.disabled)!=-1&&!d(j).hasClass("ui-tabs-selected")?"addClass":"removeClass"]("ui-state-disabled");c.cache===false&&this.anchors.removeData("cache.tabs");this.lis.add(this.anchors).unbind(".tabs");if(c.event!=="mouseover"){var k=function(g,f){f.is(":not(.ui-state-disabled)")&&f.addClass("ui-state-"+g)},n=function(g,f){f.removeClass("ui-state-"+
|
451 |
-
g)};this.lis.bind("mouseover.tabs",function(){k("hover",d(this))});this.lis.bind("mouseout.tabs",function(){n("hover",d(this))});this.anchors.bind("focus.tabs",function(){k("focus",d(this).closest("li"))});this.anchors.bind("blur.tabs",function(){n("focus",d(this).closest("li"))})}var m,o;if(c.fx)if(d.isArray(c.fx)){m=c.fx[0];o=c.fx[1]}else m=o=c.fx;var r=o?function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.hide().removeClass("ui-tabs-hide").animate(o,o.duration||"normal",
|
452 |
-
function(){e(f,o);a._trigger("show",null,a._ui(g,f[0]))})}:function(g,f){d(g).closest("li").addClass("ui-tabs-selected ui-state-active");f.removeClass("ui-tabs-hide");a._trigger("show",null,a._ui(g,f[0]))},s=m?function(g,f){f.animate(m,m.duration||"normal",function(){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");e(f,m);a.element.dequeue("tabs")})}:function(g,f){a.lis.removeClass("ui-tabs-selected ui-state-active");f.addClass("ui-tabs-hide");a.element.dequeue("tabs")};
|
453 |
-
this.anchors.bind(c.event+".tabs",function(){var g=this,f=d(g).closest("li"),i=a.panels.filter(":not(.ui-tabs-hide)"),l=a.element.find(a._sanitizeSelector(g.hash));if(f.hasClass("ui-tabs-selected")&&!c.collapsible||f.hasClass("ui-state-disabled")||f.hasClass("ui-state-processing")||a.panels.filter(":animated").length||a._trigger("select",null,a._ui(this,l[0]))===false){this.blur();return false}c.selected=a.anchors.index(this);a.abort();if(c.collapsible)if(f.hasClass("ui-tabs-selected")){c.selected=
|
454 |
-
-1;c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){s(g,i)}).dequeue("tabs");this.blur();return false}else if(!i.length){c.cookie&&a._cookie(c.selected,c.cookie);a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this));this.blur();return false}c.cookie&&a._cookie(c.selected,c.cookie);if(l.length){i.length&&a.element.queue("tabs",function(){s(g,i)});a.element.queue("tabs",function(){r(g,l)});a.load(a.anchors.index(this))}else throw"jQuery UI Tabs: Mismatching fragment identifier.";
|
455 |
-
d.browser.msie&&this.blur()});this.anchors.bind("click.tabs",function(){return false})},_getIndex:function(b){if(typeof b=="string")b=this.anchors.index(this.anchors.filter("[href$="+b+"]"));return b},destroy:function(){var b=this.options;this.abort();this.element.unbind(".tabs").removeClass("ui-tabs ui-widget ui-widget-content ui-corner-all ui-tabs-collapsible").removeData("tabs");this.list.removeClass("ui-tabs-nav ui-helper-reset ui-helper-clearfix ui-widget-header ui-corner-all");this.anchors.each(function(){var e=
|
456 |
-
d.data(this,"href.tabs");if(e)this.href=e;var a=d(this).unbind(".tabs");d.each(["href","load","cache"],function(c,h){a.removeData(h+".tabs")})});this.lis.unbind(".tabs").add(this.panels).each(function(){d.data(this,"destroy.tabs")?d(this).remove():d(this).removeClass("ui-state-default ui-corner-top ui-tabs-selected ui-state-active ui-state-hover ui-state-focus ui-state-disabled ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide")});b.cookie&&this._cookie(null,b.cookie);return this},add:function(b,
|
457 |
-
e,a){if(a===p)a=this.anchors.length;var c=this,h=this.options;e=d(h.tabTemplate.replace(/#\{href\}/g,b).replace(/#\{label\}/g,e));b=!b.indexOf("#")?b.replace("#",""):this._tabId(d("a",e)[0]);e.addClass("ui-state-default ui-corner-top").data("destroy.tabs",true);var j=c.element.find("#"+b);j.length||(j=d(h.panelTemplate).attr("id",b).data("destroy.tabs",true));j.addClass("ui-tabs-panel ui-widget-content ui-corner-bottom ui-tabs-hide");if(a>=this.lis.length){e.appendTo(this.list);j.appendTo(this.list[0].parentNode)}else{e.insertBefore(this.lis[a]);
|
458 |
-
j.insertBefore(this.panels[a])}h.disabled=d.map(h.disabled,function(k){return k>=a?++k:k});this._tabify();if(this.anchors.length==1){h.selected=0;e.addClass("ui-tabs-selected ui-state-active");j.removeClass("ui-tabs-hide");this.element.queue("tabs",function(){c._trigger("show",null,c._ui(c.anchors[0],c.panels[0]))});this.load(0)}this._trigger("add",null,this._ui(this.anchors[a],this.panels[a]));return this},remove:function(b){b=this._getIndex(b);var e=this.options,a=this.lis.eq(b).remove(),c=this.panels.eq(b).remove();
|
459 |
-
if(a.hasClass("ui-tabs-selected")&&this.anchors.length>1)this.select(b+(b+1<this.anchors.length?1:-1));e.disabled=d.map(d.grep(e.disabled,function(h){return h!=b}),function(h){return h>=b?--h:h});this._tabify();this._trigger("remove",null,this._ui(a.find("a")[0],c[0]));return this},enable:function(b){b=this._getIndex(b);var e=this.options;if(d.inArray(b,e.disabled)!=-1){this.lis.eq(b).removeClass("ui-state-disabled");e.disabled=d.grep(e.disabled,function(a){return a!=b});this._trigger("enable",null,
|
460 |
-
this._ui(this.anchors[b],this.panels[b]));return this}},disable:function(b){b=this._getIndex(b);var e=this.options;if(b!=e.selected){this.lis.eq(b).addClass("ui-state-disabled");e.disabled.push(b);e.disabled.sort();this._trigger("disable",null,this._ui(this.anchors[b],this.panels[b]))}return this},select:function(b){b=this._getIndex(b);if(b==-1)if(this.options.collapsible&&this.options.selected!=-1)b=this.options.selected;else return this;this.anchors.eq(b).trigger(this.options.event+".tabs");return this},
|
461 |
-
load:function(b){b=this._getIndex(b);var e=this,a=this.options,c=this.anchors.eq(b)[0],h=d.data(c,"load.tabs");this.abort();if(!h||this.element.queue("tabs").length!==0&&d.data(c,"cache.tabs"))this.element.dequeue("tabs");else{this.lis.eq(b).addClass("ui-state-processing");if(a.spinner){var j=d("span",c);j.data("label.tabs",j.html()).html(a.spinner)}this.xhr=d.ajax(d.extend({},a.ajaxOptions,{url:h,success:function(k,n){e.element.find(e._sanitizeSelector(c.hash)).html(k);e._cleanup();a.cache&&d.data(c,
|
462 |
-
"cache.tabs",true);e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.success(k,n)}catch(m){}},error:function(k,n){e._cleanup();e._trigger("load",null,e._ui(e.anchors[b],e.panels[b]));try{a.ajaxOptions.error(k,n,b,c)}catch(m){}}}));e.element.dequeue("tabs");return this}},abort:function(){this.element.queue([]);this.panels.stop(false,true);this.element.queue("tabs",this.element.queue("tabs").splice(-2,2));if(this.xhr){this.xhr.abort();delete this.xhr}this._cleanup();return this},
|
463 |
-
url:function(b,e){this.anchors.eq(b).removeData("cache.tabs").data("load.tabs",e);return this},length:function(){return this.anchors.length}});d.extend(d.ui.tabs,{version:"1.8.9"});d.extend(d.ui.tabs.prototype,{rotation:null,rotate:function(b,e){var a=this,c=this.options,h=a._rotate||(a._rotate=function(j){clearTimeout(a.rotation);a.rotation=setTimeout(function(){var k=c.selected;a.select(++k<a.anchors.length?k:0)},b);j&&j.stopPropagation()});e=a._unrotate||(a._unrotate=!e?function(j){j.clientX&&
|
464 |
-
a.rotate(null)}:function(){t=c.selected;h()});if(b){this.element.bind("tabsshow",h);this.anchors.bind(c.event+".tabs",e);h()}else{clearTimeout(a.rotation);this.element.unbind("tabsshow",h);this.anchors.unbind(c.event+".tabs",e);delete this._rotate;delete this._unrotate}return this}})})(jQuery);
|
465 |
-
;/*
|
466 |
-
* jQuery UI Datepicker 1.8.9
|
467 |
-
*
|
468 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
469 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
470 |
-
* http://jquery.org/license
|
471 |
-
*
|
472 |
-
* http://docs.jquery.com/UI/Datepicker
|
473 |
-
*
|
474 |
-
* Depends:
|
475 |
-
* jquery.ui.core.js
|
476 |
-
*/
|
477 |
-
(function(d,G){function K(){this.debug=false;this._curInst=null;this._keyEvent=false;this._disabledInputs=[];this._inDialog=this._datepickerShowing=false;this._mainDivId="ui-datepicker-div";this._inlineClass="ui-datepicker-inline";this._appendClass="ui-datepicker-append";this._triggerClass="ui-datepicker-trigger";this._dialogClass="ui-datepicker-dialog";this._disableClass="ui-datepicker-disabled";this._unselectableClass="ui-datepicker-unselectable";this._currentClass="ui-datepicker-current-day";this._dayOverClass=
|
478 |
-
"ui-datepicker-days-cell-over";this.regional=[];this.regional[""]={closeText:"Done",prevText:"Prev",nextText:"Next",currentText:"Today",monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],monthNamesShort:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],dayNamesShort:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],dayNamesMin:["Su",
|
479 |
-
"Mo","Tu","We","Th","Fr","Sa"],weekHeader:"Wk",dateFormat:"mm/dd/yy",firstDay:0,isRTL:false,showMonthAfterYear:false,yearSuffix:""};this._defaults={showOn:"focus",showAnim:"fadeIn",showOptions:{},defaultDate:null,appendText:"",buttonText:"...",buttonImage:"",buttonImageOnly:false,hideIfNoPrevNext:false,navigationAsDateFormat:false,gotoCurrent:false,changeMonth:false,changeYear:false,yearRange:"c-10:c+10",showOtherMonths:false,selectOtherMonths:false,showWeek:false,calculateWeek:this.iso8601Week,shortYearCutoff:"+10",
|
480 |
-
minDate:null,maxDate:null,duration:"fast",beforeShowDay:null,beforeShow:null,onSelect:null,onChangeMonthYear:null,onClose:null,numberOfMonths:1,showCurrentAtPos:0,stepMonths:1,stepBigMonths:12,altField:"",altFormat:"",constrainInput:true,showButtonPanel:false,autoSize:false};d.extend(this._defaults,this.regional[""]);this.dpDiv=d('<div id="'+this._mainDivId+'" class="ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')}function E(a,b){d.extend(a,b);for(var c in b)if(b[c]==
|
481 |
-
null||b[c]==G)a[c]=b[c];return a}d.extend(d.ui,{datepicker:{version:"1.8.9"}});var y=(new Date).getTime();d.extend(K.prototype,{markerClassName:"hasDatepicker",log:function(){this.debug&&console.log.apply("",arguments)},_widgetDatepicker:function(){return this.dpDiv},setDefaults:function(a){E(this._defaults,a||{});return this},_attachDatepicker:function(a,b){var c=null;for(var e in this._defaults){var f=a.getAttribute("date:"+e);if(f){c=c||{};try{c[e]=eval(f)}catch(h){c[e]=f}}}e=a.nodeName.toLowerCase();
|
482 |
-
f=e=="div"||e=="span";if(!a.id){this.uuid+=1;a.id="dp"+this.uuid}var i=this._newInst(d(a),f);i.settings=d.extend({},b||{},c||{});if(e=="input")this._connectDatepicker(a,i);else f&&this._inlineDatepicker(a,i)},_newInst:function(a,b){return{id:a[0].id.replace(/([^A-Za-z0-9_-])/g,"\\\\$1"),input:a,selectedDay:0,selectedMonth:0,selectedYear:0,drawMonth:0,drawYear:0,inline:b,dpDiv:!b?this.dpDiv:d('<div class="'+this._inlineClass+' ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all"></div>')}},
|
483 |
-
_connectDatepicker:function(a,b){var c=d(a);b.append=d([]);b.trigger=d([]);if(!c.hasClass(this.markerClassName)){this._attachments(c,b);c.addClass(this.markerClassName).keydown(this._doKeyDown).keypress(this._doKeyPress).keyup(this._doKeyUp).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});this._autoSize(b);d.data(a,"datepicker",b)}},_attachments:function(a,b){var c=this._get(b,"appendText"),e=this._get(b,"isRTL");b.append&&
|
484 |
-
b.append.remove();if(c){b.append=d('<span class="'+this._appendClass+'">'+c+"</span>");a[e?"before":"after"](b.append)}a.unbind("focus",this._showDatepicker);b.trigger&&b.trigger.remove();c=this._get(b,"showOn");if(c=="focus"||c=="both")a.focus(this._showDatepicker);if(c=="button"||c=="both"){c=this._get(b,"buttonText");var f=this._get(b,"buttonImage");b.trigger=d(this._get(b,"buttonImageOnly")?d("<img/>").addClass(this._triggerClass).attr({src:f,alt:c,title:c}):d('<button type="button"></button>').addClass(this._triggerClass).html(f==
|
485 |
-
""?c:d("<img/>").attr({src:f,alt:c,title:c})));a[e?"before":"after"](b.trigger);b.trigger.click(function(){d.datepicker._datepickerShowing&&d.datepicker._lastInput==a[0]?d.datepicker._hideDatepicker():d.datepicker._showDatepicker(a[0]);return false})}},_autoSize:function(a){if(this._get(a,"autoSize")&&!a.inline){var b=new Date(2009,11,20),c=this._get(a,"dateFormat");if(c.match(/[DM]/)){var e=function(f){for(var h=0,i=0,g=0;g<f.length;g++)if(f[g].length>h){h=f[g].length;i=g}return i};b.setMonth(e(this._get(a,
|
486 |
-
c.match(/MM/)?"monthNames":"monthNamesShort")));b.setDate(e(this._get(a,c.match(/DD/)?"dayNames":"dayNamesShort"))+20-b.getDay())}a.input.attr("size",this._formatDate(a,b).length)}},_inlineDatepicker:function(a,b){var c=d(a);if(!c.hasClass(this.markerClassName)){c.addClass(this.markerClassName).append(b.dpDiv).bind("setData.datepicker",function(e,f,h){b.settings[f]=h}).bind("getData.datepicker",function(e,f){return this._get(b,f)});d.data(a,"datepicker",b);this._setDate(b,this._getDefaultDate(b),
|
487 |
-
true);this._updateDatepicker(b);this._updateAlternate(b);b.dpDiv.show()}},_dialogDatepicker:function(a,b,c,e,f){a=this._dialogInst;if(!a){this.uuid+=1;this._dialogInput=d('<input type="text" id="'+("dp"+this.uuid)+'" style="position: absolute; top: -100px; width: 0px; z-index: -10;"/>');this._dialogInput.keydown(this._doKeyDown);d("body").append(this._dialogInput);a=this._dialogInst=this._newInst(this._dialogInput,false);a.settings={};d.data(this._dialogInput[0],"datepicker",a)}E(a.settings,e||{});
|
488 |
-
b=b&&b.constructor==Date?this._formatDate(a,b):b;this._dialogInput.val(b);this._pos=f?f.length?f:[f.pageX,f.pageY]:null;if(!this._pos)this._pos=[document.documentElement.clientWidth/2-100+(document.documentElement.scrollLeft||document.body.scrollLeft),document.documentElement.clientHeight/2-150+(document.documentElement.scrollTop||document.body.scrollTop)];this._dialogInput.css("left",this._pos[0]+20+"px").css("top",this._pos[1]+"px");a.settings.onSelect=c;this._inDialog=true;this.dpDiv.addClass(this._dialogClass);
|
489 |
-
this._showDatepicker(this._dialogInput[0]);d.blockUI&&d.blockUI(this.dpDiv);d.data(this._dialogInput[0],"datepicker",a);return this},_destroyDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();d.removeData(a,"datepicker");if(e=="input"){c.append.remove();c.trigger.remove();b.removeClass(this.markerClassName).unbind("focus",this._showDatepicker).unbind("keydown",this._doKeyDown).unbind("keypress",this._doKeyPress).unbind("keyup",
|
490 |
-
this._doKeyUp)}else if(e=="div"||e=="span")b.removeClass(this.markerClassName).empty()}},_enableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=false;c.trigger.filter("button").each(function(){this.disabled=false}).end().filter("img").css({opacity:"1.0",cursor:""})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().removeClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,
|
491 |
-
function(f){return f==a?null:f})}},_disableDatepicker:function(a){var b=d(a),c=d.data(a,"datepicker");if(b.hasClass(this.markerClassName)){var e=a.nodeName.toLowerCase();if(e=="input"){a.disabled=true;c.trigger.filter("button").each(function(){this.disabled=true}).end().filter("img").css({opacity:"0.5",cursor:"default"})}else if(e=="div"||e=="span")b.children("."+this._inlineClass).children().addClass("ui-state-disabled");this._disabledInputs=d.map(this._disabledInputs,function(f){return f==a?null:
|
492 |
-
f});this._disabledInputs[this._disabledInputs.length]=a}},_isDisabledDatepicker:function(a){if(!a)return false;for(var b=0;b<this._disabledInputs.length;b++)if(this._disabledInputs[b]==a)return true;return false},_getInst:function(a){try{return d.data(a,"datepicker")}catch(b){throw"Missing instance data for this datepicker";}},_optionDatepicker:function(a,b,c){var e=this._getInst(a);if(arguments.length==2&&typeof b=="string")return b=="defaults"?d.extend({},d.datepicker._defaults):e?b=="all"?d.extend({},
|
493 |
-
e.settings):this._get(e,b):null;var f=b||{};if(typeof b=="string"){f={};f[b]=c}if(e){this._curInst==e&&this._hideDatepicker();var h=this._getDateDatepicker(a,true);E(e.settings,f);this._attachments(d(a),e);this._autoSize(e);this._setDateDatepicker(a,h);this._updateDatepicker(e)}},_changeDatepicker:function(a,b,c){this._optionDatepicker(a,b,c)},_refreshDatepicker:function(a){(a=this._getInst(a))&&this._updateDatepicker(a)},_setDateDatepicker:function(a,b){if(a=this._getInst(a)){this._setDate(a,b);
|
494 |
-
this._updateDatepicker(a);this._updateAlternate(a)}},_getDateDatepicker:function(a,b){(a=this._getInst(a))&&!a.inline&&this._setDateFromField(a,b);return a?this._getDate(a):null},_doKeyDown:function(a){var b=d.datepicker._getInst(a.target),c=true,e=b.dpDiv.is(".ui-datepicker-rtl");b._keyEvent=true;if(d.datepicker._datepickerShowing)switch(a.keyCode){case 9:d.datepicker._hideDatepicker();c=false;break;case 13:c=d("td."+d.datepicker._dayOverClass+":not(."+d.datepicker._currentClass+")",b.dpDiv);c[0]?
|
495 |
-
d.datepicker._selectDay(a.target,b.selectedMonth,b.selectedYear,c[0]):d.datepicker._hideDatepicker();return false;case 27:d.datepicker._hideDatepicker();break;case 33:d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 34:d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 35:if(a.ctrlKey||a.metaKey)d.datepicker._clearDate(a.target);c=a.ctrlKey||
|
496 |
-
a.metaKey;break;case 36:if(a.ctrlKey||a.metaKey)d.datepicker._gotoToday(a.target);c=a.ctrlKey||a.metaKey;break;case 37:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,e?+1:-1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?-d.datepicker._get(b,"stepBigMonths"):-d.datepicker._get(b,"stepMonths"),"M");break;case 38:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,-7,"D");c=a.ctrlKey||a.metaKey;break;case 39:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,
|
497 |
-
e?-1:+1,"D");c=a.ctrlKey||a.metaKey;if(a.originalEvent.altKey)d.datepicker._adjustDate(a.target,a.ctrlKey?+d.datepicker._get(b,"stepBigMonths"):+d.datepicker._get(b,"stepMonths"),"M");break;case 40:if(a.ctrlKey||a.metaKey)d.datepicker._adjustDate(a.target,+7,"D");c=a.ctrlKey||a.metaKey;break;default:c=false}else if(a.keyCode==36&&a.ctrlKey)d.datepicker._showDatepicker(this);else c=false;if(c){a.preventDefault();a.stopPropagation()}},_doKeyPress:function(a){var b=d.datepicker._getInst(a.target);if(d.datepicker._get(b,
|
498 |
-
"constrainInput")){b=d.datepicker._possibleChars(d.datepicker._get(b,"dateFormat"));var c=String.fromCharCode(a.charCode==G?a.keyCode:a.charCode);return a.ctrlKey||a.metaKey||c<" "||!b||b.indexOf(c)>-1}},_doKeyUp:function(a){a=d.datepicker._getInst(a.target);if(a.input.val()!=a.lastVal)try{if(d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),a.input?a.input.val():null,d.datepicker._getFormatConfig(a))){d.datepicker._setDateFromField(a);d.datepicker._updateAlternate(a);d.datepicker._updateDatepicker(a)}}catch(b){d.datepicker.log(b)}return true},
|
499 |
-
_showDatepicker:function(a){a=a.target||a;if(a.nodeName.toLowerCase()!="input")a=d("input",a.parentNode)[0];if(!(d.datepicker._isDisabledDatepicker(a)||d.datepicker._lastInput==a)){var b=d.datepicker._getInst(a);d.datepicker._curInst&&d.datepicker._curInst!=b&&d.datepicker._curInst.dpDiv.stop(true,true);var c=d.datepicker._get(b,"beforeShow");E(b.settings,c?c.apply(a,[a,b]):{});b.lastVal=null;d.datepicker._lastInput=a;d.datepicker._setDateFromField(b);if(d.datepicker._inDialog)a.value="";if(!d.datepicker._pos){d.datepicker._pos=
|
500 |
-
d.datepicker._findPos(a);d.datepicker._pos[1]+=a.offsetHeight}var e=false;d(a).parents().each(function(){e|=d(this).css("position")=="fixed";return!e});if(e&&d.browser.opera){d.datepicker._pos[0]-=document.documentElement.scrollLeft;d.datepicker._pos[1]-=document.documentElement.scrollTop}c={left:d.datepicker._pos[0],top:d.datepicker._pos[1]};d.datepicker._pos=null;b.dpDiv.empty();b.dpDiv.css({position:"absolute",display:"block",top:"-1000px"});d.datepicker._updateDatepicker(b);c=d.datepicker._checkOffset(b,
|
501 |
-
c,e);b.dpDiv.css({position:d.datepicker._inDialog&&d.blockUI?"static":e?"fixed":"absolute",display:"none",left:c.left+"px",top:c.top+"px"});if(!b.inline){c=d.datepicker._get(b,"showAnim");var f=d.datepicker._get(b,"duration"),h=function(){d.datepicker._datepickerShowing=true;var i=b.dpDiv.find("iframe.ui-datepicker-cover");if(i.length){var g=d.datepicker._getBorders(b.dpDiv);i.css({left:-g[0],top:-g[1],width:b.dpDiv.outerWidth(),height:b.dpDiv.outerHeight()})}};b.dpDiv.zIndex(d(a).zIndex()+1);d.effects&&
|
502 |
-
d.effects[c]?b.dpDiv.show(c,d.datepicker._get(b,"showOptions"),f,h):b.dpDiv[c||"show"](c?f:null,h);if(!c||!f)h();b.input.is(":visible")&&!b.input.is(":disabled")&&b.input.focus();d.datepicker._curInst=b}}},_updateDatepicker:function(a){var b=this,c=d.datepicker._getBorders(a.dpDiv);a.dpDiv.empty().append(this._generateHTML(a));var e=a.dpDiv.find("iframe.ui-datepicker-cover");e.length&&e.css({left:-c[0],top:-c[1],width:a.dpDiv.outerWidth(),height:a.dpDiv.outerHeight()});a.dpDiv.find("button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a").bind("mouseout",
|
503 |
-
function(){d(this).removeClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=-1&&d(this).removeClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).removeClass("ui-datepicker-next-hover")}).bind("mouseover",function(){if(!b._isDisabledDatepicker(a.inline?a.dpDiv.parent()[0]:a.input[0])){d(this).parents(".ui-datepicker-calendar").find("a").removeClass("ui-state-hover");d(this).addClass("ui-state-hover");this.className.indexOf("ui-datepicker-prev")!=
|
504 |
-
-1&&d(this).addClass("ui-datepicker-prev-hover");this.className.indexOf("ui-datepicker-next")!=-1&&d(this).addClass("ui-datepicker-next-hover")}}).end().find("."+this._dayOverClass+" a").trigger("mouseover").end();c=this._getNumberOfMonths(a);e=c[1];e>1?a.dpDiv.addClass("ui-datepicker-multi-"+e).css("width",17*e+"em"):a.dpDiv.removeClass("ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4").width("");a.dpDiv[(c[0]!=1||c[1]!=1?"add":"remove")+"Class"]("ui-datepicker-multi");a.dpDiv[(this._get(a,
|
505 |
-
"isRTL")?"add":"remove")+"Class"]("ui-datepicker-rtl");a==d.datepicker._curInst&&d.datepicker._datepickerShowing&&a.input&&a.input.is(":visible")&&!a.input.is(":disabled")&&a.input.focus();if(a.yearshtml){var f=a.yearshtml;setTimeout(function(){f===a.yearshtml&&a.dpDiv.find("select.ui-datepicker-year:first").replaceWith(a.yearshtml);f=a.yearshtml=null},0)}},_getBorders:function(a){var b=function(c){return{thin:1,medium:2,thick:3}[c]||c};return[parseFloat(b(a.css("border-left-width"))),parseFloat(b(a.css("border-top-width")))]},
|
506 |
-
_checkOffset:function(a,b,c){var e=a.dpDiv.outerWidth(),f=a.dpDiv.outerHeight(),h=a.input?a.input.outerWidth():0,i=a.input?a.input.outerHeight():0,g=document.documentElement.clientWidth+d(document).scrollLeft(),j=document.documentElement.clientHeight+d(document).scrollTop();b.left-=this._get(a,"isRTL")?e-h:0;b.left-=c&&b.left==a.input.offset().left?d(document).scrollLeft():0;b.top-=c&&b.top==a.input.offset().top+i?d(document).scrollTop():0;b.left-=Math.min(b.left,b.left+e>g&&g>e?Math.abs(b.left+e-
|
507 |
-
g):0);b.top-=Math.min(b.top,b.top+f>j&&j>f?Math.abs(f+i):0);return b},_findPos:function(a){for(var b=this._get(this._getInst(a),"isRTL");a&&(a.type=="hidden"||a.nodeType!=1);)a=a[b?"previousSibling":"nextSibling"];a=d(a).offset();return[a.left,a.top]},_hideDatepicker:function(a){var b=this._curInst;if(!(!b||a&&b!=d.data(a,"datepicker")))if(this._datepickerShowing){a=this._get(b,"showAnim");var c=this._get(b,"duration"),e=function(){d.datepicker._tidyDialog(b);this._curInst=null};d.effects&&d.effects[a]?
|
508 |
-
b.dpDiv.hide(a,d.datepicker._get(b,"showOptions"),c,e):b.dpDiv[a=="slideDown"?"slideUp":a=="fadeIn"?"fadeOut":"hide"](a?c:null,e);a||e();if(a=this._get(b,"onClose"))a.apply(b.input?b.input[0]:null,[b.input?b.input.val():"",b]);this._datepickerShowing=false;this._lastInput=null;if(this._inDialog){this._dialogInput.css({position:"absolute",left:"0",top:"-100px"});if(d.blockUI){d.unblockUI();d("body").append(this.dpDiv)}}this._inDialog=false}},_tidyDialog:function(a){a.dpDiv.removeClass(this._dialogClass).unbind(".ui-datepicker-calendar")},
|
509 |
-
_checkExternalClick:function(a){if(d.datepicker._curInst){a=d(a.target);a[0].id!=d.datepicker._mainDivId&&a.parents("#"+d.datepicker._mainDivId).length==0&&!a.hasClass(d.datepicker.markerClassName)&&!a.hasClass(d.datepicker._triggerClass)&&d.datepicker._datepickerShowing&&!(d.datepicker._inDialog&&d.blockUI)&&d.datepicker._hideDatepicker()}},_adjustDate:function(a,b,c){a=d(a);var e=this._getInst(a[0]);if(!this._isDisabledDatepicker(a[0])){this._adjustInstDate(e,b+(c=="M"?this._get(e,"showCurrentAtPos"):
|
510 |
-
0),c);this._updateDatepicker(e)}},_gotoToday:function(a){a=d(a);var b=this._getInst(a[0]);if(this._get(b,"gotoCurrent")&&b.currentDay){b.selectedDay=b.currentDay;b.drawMonth=b.selectedMonth=b.currentMonth;b.drawYear=b.selectedYear=b.currentYear}else{var c=new Date;b.selectedDay=c.getDate();b.drawMonth=b.selectedMonth=c.getMonth();b.drawYear=b.selectedYear=c.getFullYear()}this._notifyChange(b);this._adjustDate(a)},_selectMonthYear:function(a,b,c){a=d(a);var e=this._getInst(a[0]);e._selectingMonthYear=
|
511 |
-
false;e["selected"+(c=="M"?"Month":"Year")]=e["draw"+(c=="M"?"Month":"Year")]=parseInt(b.options[b.selectedIndex].value,10);this._notifyChange(e);this._adjustDate(a)},_clickMonthYear:function(a){var b=this._getInst(d(a)[0]);b.input&&b._selectingMonthYear&&setTimeout(function(){b.input.focus()},0);b._selectingMonthYear=!b._selectingMonthYear},_selectDay:function(a,b,c,e){var f=d(a);if(!(d(e).hasClass(this._unselectableClass)||this._isDisabledDatepicker(f[0]))){f=this._getInst(f[0]);f.selectedDay=f.currentDay=
|
512 |
-
d("a",e).html();f.selectedMonth=f.currentMonth=b;f.selectedYear=f.currentYear=c;this._selectDate(a,this._formatDate(f,f.currentDay,f.currentMonth,f.currentYear))}},_clearDate:function(a){a=d(a);this._getInst(a[0]);this._selectDate(a,"")},_selectDate:function(a,b){a=this._getInst(d(a)[0]);b=b!=null?b:this._formatDate(a);a.input&&a.input.val(b);this._updateAlternate(a);var c=this._get(a,"onSelect");if(c)c.apply(a.input?a.input[0]:null,[b,a]);else a.input&&a.input.trigger("change");if(a.inline)this._updateDatepicker(a);
|
513 |
-
else{this._hideDatepicker();this._lastInput=a.input[0];typeof a.input[0]!="object"&&a.input.focus();this._lastInput=null}},_updateAlternate:function(a){var b=this._get(a,"altField");if(b){var c=this._get(a,"altFormat")||this._get(a,"dateFormat"),e=this._getDate(a),f=this.formatDate(c,e,this._getFormatConfig(a));d(b).each(function(){d(this).val(f)})}},noWeekends:function(a){a=a.getDay();return[a>0&&a<6,""]},iso8601Week:function(a){a=new Date(a.getTime());a.setDate(a.getDate()+4-(a.getDay()||7));var b=
|
514 |
-
a.getTime();a.setMonth(0);a.setDate(1);return Math.floor(Math.round((b-a)/864E5)/7)+1},parseDate:function(a,b,c){if(a==null||b==null)throw"Invalid arguments";b=typeof b=="object"?b.toString():b+"";if(b=="")return null;var e=(c?c.shortYearCutoff:null)||this._defaults.shortYearCutoff;e=typeof e!="string"?e:(new Date).getFullYear()%100+parseInt(e,10);for(var f=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,h=(c?c.dayNames:null)||this._defaults.dayNames,i=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort,
|
515 |
-
g=(c?c.monthNames:null)||this._defaults.monthNames,j=c=-1,l=-1,u=-1,k=false,o=function(p){(p=z+1<a.length&&a.charAt(z+1)==p)&&z++;return p},m=function(p){var v=o(p);p=new RegExp("^\\d{1,"+(p=="@"?14:p=="!"?20:p=="y"&&v?4:p=="o"?3:2)+"}");p=b.substring(s).match(p);if(!p)throw"Missing number at position "+s;s+=p[0].length;return parseInt(p[0],10)},n=function(p,v,H){p=o(p)?H:v;for(v=0;v<p.length;v++)if(b.substr(s,p[v].length).toLowerCase()==p[v].toLowerCase()){s+=p[v].length;return v+1}throw"Unknown name at position "+
|
516 |
-
s;},r=function(){if(b.charAt(s)!=a.charAt(z))throw"Unexpected literal at position "+s;s++},s=0,z=0;z<a.length;z++)if(k)if(a.charAt(z)=="'"&&!o("'"))k=false;else r();else switch(a.charAt(z)){case "d":l=m("d");break;case "D":n("D",f,h);break;case "o":u=m("o");break;case "m":j=m("m");break;case "M":j=n("M",i,g);break;case "y":c=m("y");break;case "@":var w=new Date(m("@"));c=w.getFullYear();j=w.getMonth()+1;l=w.getDate();break;case "!":w=new Date((m("!")-this._ticksTo1970)/1E4);c=w.getFullYear();j=w.getMonth()+
|
517 |
-
1;l=w.getDate();break;case "'":if(o("'"))r();else k=true;break;default:r()}if(c==-1)c=(new Date).getFullYear();else if(c<100)c+=(new Date).getFullYear()-(new Date).getFullYear()%100+(c<=e?0:-100);if(u>-1){j=1;l=u;do{e=this._getDaysInMonth(c,j-1);if(l<=e)break;j++;l-=e}while(1)}w=this._daylightSavingAdjust(new Date(c,j-1,l));if(w.getFullYear()!=c||w.getMonth()+1!=j||w.getDate()!=l)throw"Invalid date";return w},ATOM:"yy-mm-dd",COOKIE:"D, dd M yy",ISO_8601:"yy-mm-dd",RFC_822:"D, d M y",RFC_850:"DD, dd-M-y",
|
518 |
-
RFC_1036:"D, d M y",RFC_1123:"D, d M yy",RFC_2822:"D, d M yy",RSS:"D, d M y",TICKS:"!",TIMESTAMP:"@",W3C:"yy-mm-dd",_ticksTo1970:(718685+Math.floor(492.5)-Math.floor(19.7)+Math.floor(4.925))*24*60*60*1E7,formatDate:function(a,b,c){if(!b)return"";var e=(c?c.dayNamesShort:null)||this._defaults.dayNamesShort,f=(c?c.dayNames:null)||this._defaults.dayNames,h=(c?c.monthNamesShort:null)||this._defaults.monthNamesShort;c=(c?c.monthNames:null)||this._defaults.monthNames;var i=function(o){(o=k+1<a.length&&
|
519 |
-
a.charAt(k+1)==o)&&k++;return o},g=function(o,m,n){m=""+m;if(i(o))for(;m.length<n;)m="0"+m;return m},j=function(o,m,n,r){return i(o)?r[m]:n[m]},l="",u=false;if(b)for(var k=0;k<a.length;k++)if(u)if(a.charAt(k)=="'"&&!i("'"))u=false;else l+=a.charAt(k);else switch(a.charAt(k)){case "d":l+=g("d",b.getDate(),2);break;case "D":l+=j("D",b.getDay(),e,f);break;case "o":l+=g("o",(b.getTime()-(new Date(b.getFullYear(),0,0)).getTime())/864E5,3);break;case "m":l+=g("m",b.getMonth()+1,2);break;case "M":l+=j("M",
|
520 |
-
b.getMonth(),h,c);break;case "y":l+=i("y")?b.getFullYear():(b.getYear()%100<10?"0":"")+b.getYear()%100;break;case "@":l+=b.getTime();break;case "!":l+=b.getTime()*1E4+this._ticksTo1970;break;case "'":if(i("'"))l+="'";else u=true;break;default:l+=a.charAt(k)}return l},_possibleChars:function(a){for(var b="",c=false,e=function(h){(h=f+1<a.length&&a.charAt(f+1)==h)&&f++;return h},f=0;f<a.length;f++)if(c)if(a.charAt(f)=="'"&&!e("'"))c=false;else b+=a.charAt(f);else switch(a.charAt(f)){case "d":case "m":case "y":case "@":b+=
|
521 |
-
"0123456789";break;case "D":case "M":return null;case "'":if(e("'"))b+="'";else c=true;break;default:b+=a.charAt(f)}return b},_get:function(a,b){return a.settings[b]!==G?a.settings[b]:this._defaults[b]},_setDateFromField:function(a,b){if(a.input.val()!=a.lastVal){var c=this._get(a,"dateFormat"),e=a.lastVal=a.input?a.input.val():null,f,h;f=h=this._getDefaultDate(a);var i=this._getFormatConfig(a);try{f=this.parseDate(c,e,i)||h}catch(g){this.log(g);e=b?"":e}a.selectedDay=f.getDate();a.drawMonth=a.selectedMonth=
|
522 |
-
f.getMonth();a.drawYear=a.selectedYear=f.getFullYear();a.currentDay=e?f.getDate():0;a.currentMonth=e?f.getMonth():0;a.currentYear=e?f.getFullYear():0;this._adjustInstDate(a)}},_getDefaultDate:function(a){return this._restrictMinMax(a,this._determineDate(a,this._get(a,"defaultDate"),new Date))},_determineDate:function(a,b,c){var e=function(h){var i=new Date;i.setDate(i.getDate()+h);return i},f=function(h){try{return d.datepicker.parseDate(d.datepicker._get(a,"dateFormat"),h,d.datepicker._getFormatConfig(a))}catch(i){}var g=
|
523 |
-
(h.toLowerCase().match(/^c/)?d.datepicker._getDate(a):null)||new Date,j=g.getFullYear(),l=g.getMonth();g=g.getDate();for(var u=/([+-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,k=u.exec(h);k;){switch(k[2]||"d"){case "d":case "D":g+=parseInt(k[1],10);break;case "w":case "W":g+=parseInt(k[1],10)*7;break;case "m":case "M":l+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break;case "y":case "Y":j+=parseInt(k[1],10);g=Math.min(g,d.datepicker._getDaysInMonth(j,l));break}k=u.exec(h)}return new Date(j,
|
524 |
-
l,g)};if(b=(b=b==null||b===""?c:typeof b=="string"?f(b):typeof b=="number"?isNaN(b)?c:e(b):new Date(b.getTime()))&&b.toString()=="Invalid Date"?c:b){b.setHours(0);b.setMinutes(0);b.setSeconds(0);b.setMilliseconds(0)}return this._daylightSavingAdjust(b)},_daylightSavingAdjust:function(a){if(!a)return null;a.setHours(a.getHours()>12?a.getHours()+2:0);return a},_setDate:function(a,b,c){var e=!b,f=a.selectedMonth,h=a.selectedYear;b=this._restrictMinMax(a,this._determineDate(a,b,new Date));a.selectedDay=
|
525 |
-
a.currentDay=b.getDate();a.drawMonth=a.selectedMonth=a.currentMonth=b.getMonth();a.drawYear=a.selectedYear=a.currentYear=b.getFullYear();if((f!=a.selectedMonth||h!=a.selectedYear)&&!c)this._notifyChange(a);this._adjustInstDate(a);if(a.input)a.input.val(e?"":this._formatDate(a))},_getDate:function(a){return!a.currentYear||a.input&&a.input.val()==""?null:this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay))},_generateHTML:function(a){var b=new Date;b=this._daylightSavingAdjust(new Date(b.getFullYear(),
|
526 |
-
b.getMonth(),b.getDate()));var c=this._get(a,"isRTL"),e=this._get(a,"showButtonPanel"),f=this._get(a,"hideIfNoPrevNext"),h=this._get(a,"navigationAsDateFormat"),i=this._getNumberOfMonths(a),g=this._get(a,"showCurrentAtPos"),j=this._get(a,"stepMonths"),l=i[0]!=1||i[1]!=1,u=this._daylightSavingAdjust(!a.currentDay?new Date(9999,9,9):new Date(a.currentYear,a.currentMonth,a.currentDay)),k=this._getMinMaxDate(a,"min"),o=this._getMinMaxDate(a,"max");g=a.drawMonth-g;var m=a.drawYear;if(g<0){g+=12;m--}if(o){var n=
|
527 |
-
this._daylightSavingAdjust(new Date(o.getFullYear(),o.getMonth()-i[0]*i[1]+1,o.getDate()));for(n=k&&n<k?k:n;this._daylightSavingAdjust(new Date(m,g,1))>n;){g--;if(g<0){g=11;m--}}}a.drawMonth=g;a.drawYear=m;n=this._get(a,"prevText");n=!h?n:this.formatDate(n,this._daylightSavingAdjust(new Date(m,g-j,1)),this._getFormatConfig(a));n=this._canAdjustMonth(a,-1,m,g)?'<a class="ui-datepicker-prev ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', -"+j+", 'M');\" title=\""+n+'"><span class="ui-icon ui-icon-circle-triangle-'+
|
528 |
-
(c?"e":"w")+'">'+n+"</span></a>":f?"":'<a class="ui-datepicker-prev ui-corner-all ui-state-disabled" title="'+n+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"e":"w")+'">'+n+"</span></a>";var r=this._get(a,"nextText");r=!h?r:this.formatDate(r,this._daylightSavingAdjust(new Date(m,g+j,1)),this._getFormatConfig(a));f=this._canAdjustMonth(a,+1,m,g)?'<a class="ui-datepicker-next ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._adjustDate('#"+a.id+"', +"+j+", 'M');\" title=\""+r+'"><span class="ui-icon ui-icon-circle-triangle-'+
|
529 |
-
(c?"w":"e")+'">'+r+"</span></a>":f?"":'<a class="ui-datepicker-next ui-corner-all ui-state-disabled" title="'+r+'"><span class="ui-icon ui-icon-circle-triangle-'+(c?"w":"e")+'">'+r+"</span></a>";j=this._get(a,"currentText");r=this._get(a,"gotoCurrent")&&a.currentDay?u:b;j=!h?j:this.formatDate(j,r,this._getFormatConfig(a));h=!a.inline?'<button type="button" class="ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all" onclick="DP_jQuery_'+y+'.datepicker._hideDatepicker();">'+this._get(a,
|
530 |
-
"closeText")+"</button>":"";e=e?'<div class="ui-datepicker-buttonpane ui-widget-content">'+(c?h:"")+(this._isInRange(a,r)?'<button type="button" class="ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all" onclick="DP_jQuery_'+y+".datepicker._gotoToday('#"+a.id+"');\">"+j+"</button>":"")+(c?"":h)+"</div>":"";h=parseInt(this._get(a,"firstDay"),10);h=isNaN(h)?0:h;j=this._get(a,"showWeek");r=this._get(a,"dayNames");this._get(a,"dayNamesShort");var s=this._get(a,"dayNamesMin"),z=
|
531 |
-
this._get(a,"monthNames"),w=this._get(a,"monthNamesShort"),p=this._get(a,"beforeShowDay"),v=this._get(a,"showOtherMonths"),H=this._get(a,"selectOtherMonths");this._get(a,"calculateWeek");for(var L=this._getDefaultDate(a),I="",C=0;C<i[0];C++){for(var M="",D=0;D<i[1];D++){var N=this._daylightSavingAdjust(new Date(m,g,a.selectedDay)),t=" ui-corner-all",x="";if(l){x+='<div class="ui-datepicker-group';if(i[1]>1)switch(D){case 0:x+=" ui-datepicker-group-first";t=" ui-corner-"+(c?"right":"left");break;case i[1]-
|
532 |
-
1:x+=" ui-datepicker-group-last";t=" ui-corner-"+(c?"left":"right");break;default:x+=" ui-datepicker-group-middle";t="";break}x+='">'}x+='<div class="ui-datepicker-header ui-widget-header ui-helper-clearfix'+t+'">'+(/all|left/.test(t)&&C==0?c?f:n:"")+(/all|right/.test(t)&&C==0?c?n:f:"")+this._generateMonthYearHeader(a,g,m,k,o,C>0||D>0,z,w)+'</div><table class="ui-datepicker-calendar"><thead><tr>';var A=j?'<th class="ui-datepicker-week-col">'+this._get(a,"weekHeader")+"</th>":"";for(t=0;t<7;t++){var q=
|
533 |
-
(t+h)%7;A+="<th"+((t+h+6)%7>=5?' class="ui-datepicker-week-end"':"")+'><span title="'+r[q]+'">'+s[q]+"</span></th>"}x+=A+"</tr></thead><tbody>";A=this._getDaysInMonth(m,g);if(m==a.selectedYear&&g==a.selectedMonth)a.selectedDay=Math.min(a.selectedDay,A);t=(this._getFirstDayOfMonth(m,g)-h+7)%7;A=l?6:Math.ceil((t+A)/7);q=this._daylightSavingAdjust(new Date(m,g,1-t));for(var O=0;O<A;O++){x+="<tr>";var P=!j?"":'<td class="ui-datepicker-week-col">'+this._get(a,"calculateWeek")(q)+"</td>";for(t=0;t<7;t++){var F=
|
534 |
-
p?p.apply(a.input?a.input[0]:null,[q]):[true,""],B=q.getMonth()!=g,J=B&&!H||!F[0]||k&&q<k||o&&q>o;P+='<td class="'+((t+h+6)%7>=5?" ui-datepicker-week-end":"")+(B?" ui-datepicker-other-month":"")+(q.getTime()==N.getTime()&&g==a.selectedMonth&&a._keyEvent||L.getTime()==q.getTime()&&L.getTime()==N.getTime()?" "+this._dayOverClass:"")+(J?" "+this._unselectableClass+" ui-state-disabled":"")+(B&&!v?"":" "+F[1]+(q.getTime()==u.getTime()?" "+this._currentClass:"")+(q.getTime()==b.getTime()?" ui-datepicker-today":
|
535 |
-
""))+'"'+((!B||v)&&F[2]?' title="'+F[2]+'"':"")+(J?"":' onclick="DP_jQuery_'+y+".datepicker._selectDay('#"+a.id+"',"+q.getMonth()+","+q.getFullYear()+', this);return false;"')+">"+(B&&!v?" ":J?'<span class="ui-state-default">'+q.getDate()+"</span>":'<a class="ui-state-default'+(q.getTime()==b.getTime()?" ui-state-highlight":"")+(q.getTime()==u.getTime()?" ui-state-active":"")+(B?" ui-priority-secondary":"")+'" href="#">'+q.getDate()+"</a>")+"</td>";q.setDate(q.getDate()+1);q=this._daylightSavingAdjust(q)}x+=
|
536 |
-
P+"</tr>"}g++;if(g>11){g=0;m++}x+="</tbody></table>"+(l?"</div>"+(i[0]>0&&D==i[1]-1?'<div class="ui-datepicker-row-break"></div>':""):"");M+=x}I+=M}I+=e+(d.browser.msie&&parseInt(d.browser.version,10)<7&&!a.inline?'<iframe src="javascript:false;" class="ui-datepicker-cover" frameborder="0"></iframe>':"");a._keyEvent=false;return I},_generateMonthYearHeader:function(a,b,c,e,f,h,i,g){var j=this._get(a,"changeMonth"),l=this._get(a,"changeYear"),u=this._get(a,"showMonthAfterYear"),k='<div class="ui-datepicker-title">',
|
537 |
-
o="";if(h||!j)o+='<span class="ui-datepicker-month">'+i[b]+"</span>";else{i=e&&e.getFullYear()==c;var m=f&&f.getFullYear()==c;o+='<select class="ui-datepicker-month" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+a.id+"', this, 'M');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+a.id+"');\">";for(var n=0;n<12;n++)if((!i||n>=e.getMonth())&&(!m||n<=f.getMonth()))o+='<option value="'+n+'"'+(n==b?' selected="selected"':"")+">"+g[n]+"</option>";o+="</select>"}u||(k+=o+(h||!(j&&
|
538 |
-
l)?" ":""));a.yearshtml="";if(h||!l)k+='<span class="ui-datepicker-year">'+c+"</span>";else{g=this._get(a,"yearRange").split(":");var r=(new Date).getFullYear();i=function(s){s=s.match(/c[+-].*/)?c+parseInt(s.substring(1),10):s.match(/[+-].*/)?r+parseInt(s,10):parseInt(s,10);return isNaN(s)?r:s};b=i(g[0]);g=Math.max(b,i(g[1]||""));b=e?Math.max(b,e.getFullYear()):b;g=f?Math.min(g,f.getFullYear()):g;for(a.yearshtml+='<select class="ui-datepicker-year" onchange="DP_jQuery_'+y+".datepicker._selectMonthYear('#"+
|
539 |
-
a.id+"', this, 'Y');\" onclick=\"DP_jQuery_"+y+".datepicker._clickMonthYear('#"+a.id+"');\">";b<=g;b++)a.yearshtml+='<option value="'+b+'"'+(b==c?' selected="selected"':"")+">"+b+"</option>";a.yearshtml+="</select>";if(d.browser.mozilla)k+='<select class="ui-datepicker-year"><option value="'+c+'" selected="selected">'+c+"</option></select>";else{k+=a.yearshtml;a.yearshtml=null}}k+=this._get(a,"yearSuffix");if(u)k+=(h||!(j&&l)?" ":"")+o;k+="</div>";return k},_adjustInstDate:function(a,b,c){var e=
|
540 |
-
a.drawYear+(c=="Y"?b:0),f=a.drawMonth+(c=="M"?b:0);b=Math.min(a.selectedDay,this._getDaysInMonth(e,f))+(c=="D"?b:0);e=this._restrictMinMax(a,this._daylightSavingAdjust(new Date(e,f,b)));a.selectedDay=e.getDate();a.drawMonth=a.selectedMonth=e.getMonth();a.drawYear=a.selectedYear=e.getFullYear();if(c=="M"||c=="Y")this._notifyChange(a)},_restrictMinMax:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");b=c&&b<c?c:b;return b=a&&b>a?a:b},_notifyChange:function(a){var b=this._get(a,
|
541 |
-
"onChangeMonthYear");if(b)b.apply(a.input?a.input[0]:null,[a.selectedYear,a.selectedMonth+1,a])},_getNumberOfMonths:function(a){a=this._get(a,"numberOfMonths");return a==null?[1,1]:typeof a=="number"?[1,a]:a},_getMinMaxDate:function(a,b){return this._determineDate(a,this._get(a,b+"Date"),null)},_getDaysInMonth:function(a,b){return 32-(new Date(a,b,32)).getDate()},_getFirstDayOfMonth:function(a,b){return(new Date(a,b,1)).getDay()},_canAdjustMonth:function(a,b,c,e){var f=this._getNumberOfMonths(a);
|
542 |
-
c=this._daylightSavingAdjust(new Date(c,e+(b<0?b:f[0]*f[1]),1));b<0&&c.setDate(this._getDaysInMonth(c.getFullYear(),c.getMonth()));return this._isInRange(a,c)},_isInRange:function(a,b){var c=this._getMinMaxDate(a,"min");a=this._getMinMaxDate(a,"max");return(!c||b.getTime()>=c.getTime())&&(!a||b.getTime()<=a.getTime())},_getFormatConfig:function(a){var b=this._get(a,"shortYearCutoff");b=typeof b!="string"?b:(new Date).getFullYear()%100+parseInt(b,10);return{shortYearCutoff:b,dayNamesShort:this._get(a,
|
543 |
-
"dayNamesShort"),dayNames:this._get(a,"dayNames"),monthNamesShort:this._get(a,"monthNamesShort"),monthNames:this._get(a,"monthNames")}},_formatDate:function(a,b,c,e){if(!b){a.currentDay=a.selectedDay;a.currentMonth=a.selectedMonth;a.currentYear=a.selectedYear}b=b?typeof b=="object"?b:this._daylightSavingAdjust(new Date(e,c,b)):this._daylightSavingAdjust(new Date(a.currentYear,a.currentMonth,a.currentDay));return this.formatDate(this._get(a,"dateFormat"),b,this._getFormatConfig(a))}});d.fn.datepicker=
|
544 |
-
function(a){if(!d.datepicker.initialized){d(document).mousedown(d.datepicker._checkExternalClick).find("body").append(d.datepicker.dpDiv);d.datepicker.initialized=true}var b=Array.prototype.slice.call(arguments,1);if(typeof a=="string"&&(a=="isDisabled"||a=="getDate"||a=="widget"))return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));if(a=="option"&&arguments.length==2&&typeof arguments[1]=="string")return d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this[0]].concat(b));
|
545 |
-
return this.each(function(){typeof a=="string"?d.datepicker["_"+a+"Datepicker"].apply(d.datepicker,[this].concat(b)):d.datepicker._attachDatepicker(this,a)})};d.datepicker=new K;d.datepicker.initialized=false;d.datepicker.uuid=(new Date).getTime();d.datepicker.version="1.8.9";window["DP_jQuery_"+y]=d})(jQuery);
|
546 |
-
;/*
|
547 |
-
* jQuery UI Progressbar 1.8.9
|
548 |
-
*
|
549 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
550 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
551 |
-
* http://jquery.org/license
|
552 |
-
*
|
553 |
-
* http://docs.jquery.com/UI/Progressbar
|
554 |
-
*
|
555 |
-
* Depends:
|
556 |
-
* jquery.ui.core.js
|
557 |
-
* jquery.ui.widget.js
|
558 |
-
*/
|
559 |
-
(function(b,d){b.widget("ui.progressbar",{options:{value:0,max:100},min:0,_create:function(){this.element.addClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").attr({role:"progressbar","aria-valuemin":this.min,"aria-valuemax":this.options.max,"aria-valuenow":this._value()});this.valueDiv=b("<div class='ui-progressbar-value ui-widget-header ui-corner-left'></div>").appendTo(this.element);this.oldValue=this._value();this._refreshValue()},destroy:function(){this.element.removeClass("ui-progressbar ui-widget ui-widget-content ui-corner-all").removeAttr("role").removeAttr("aria-valuemin").removeAttr("aria-valuemax").removeAttr("aria-valuenow");
|
560 |
-
this.valueDiv.remove();b.Widget.prototype.destroy.apply(this,arguments)},value:function(a){if(a===d)return this._value();this._setOption("value",a);return this},_setOption:function(a,c){if(a==="value"){this.options.value=c;this._refreshValue();this._value()===this.options.max&&this._trigger("complete")}b.Widget.prototype._setOption.apply(this,arguments)},_value:function(){var a=this.options.value;if(typeof a!=="number")a=0;return Math.min(this.options.max,Math.max(this.min,a))},_percentage:function(){return 100*
|
561 |
-
this._value()/this.options.max},_refreshValue:function(){var a=this.value(),c=this._percentage();if(this.oldValue!==a){this.oldValue=a;this._trigger("change")}this.valueDiv.toggleClass("ui-corner-right",a===this.options.max).width(c.toFixed(0)+"%");this.element.attr("aria-valuenow",a)}});b.extend(b.ui.progressbar,{version:"1.8.9"})})(jQuery);
|
562 |
-
;/*
|
563 |
-
* jQuery UI Effects 1.8.9
|
564 |
-
*
|
565 |
-
* Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
|
566 |
-
* Dual licensed under the MIT or GPL Version 2 licenses.
|
567 |
-
* http://jquery.org/license
|
568 |
-
*
|
569 |
-
* http://docs.jquery.com/UI/Effects/
|
570 |
-
*/
|
571 |
-
jQuery.effects||function(f,j){function n(c){var a;if(c&&c.constructor==Array&&c.length==3)return c;if(a=/rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))return[parseInt(a[1],10),parseInt(a[2],10),parseInt(a[3],10)];if(a=/rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))return[parseFloat(a[1])*2.55,parseFloat(a[2])*2.55,parseFloat(a[3])*2.55];if(a=/#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))return[parseInt(a[1],
|
572 |
-
16),parseInt(a[2],16),parseInt(a[3],16)];if(a=/#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))return[parseInt(a[1]+a[1],16),parseInt(a[2]+a[2],16),parseInt(a[3]+a[3],16)];if(/rgba\(0, 0, 0, 0\)/.exec(c))return o.transparent;return o[f.trim(c).toLowerCase()]}function s(c,a){var b;do{b=f.curCSS(c,a);if(b!=""&&b!="transparent"||f.nodeName(c,"body"))break;a="backgroundColor"}while(c=c.parentNode);return n(b)}function p(){var c=document.defaultView?document.defaultView.getComputedStyle(this,null):this.currentStyle,
|
573 |
-
a={},b,d;if(c&&c.length&&c[0]&&c[c[0]])for(var e=c.length;e--;){b=c[e];if(typeof c[b]=="string"){d=b.replace(/\-(\w)/g,function(g,h){return h.toUpperCase()});a[d]=c[b]}}else for(b in c)if(typeof c[b]==="string")a[b]=c[b];return a}function q(c){var a,b;for(a in c){b=c[a];if(b==null||f.isFunction(b)||a in t||/scrollbar/.test(a)||!/color/i.test(a)&&isNaN(parseFloat(b)))delete c[a]}return c}function u(c,a){var b={_:0},d;for(d in a)if(c[d]!=a[d])b[d]=a[d];return b}function k(c,a,b,d){if(typeof c=="object"){d=
|
574 |
-
a;b=null;a=c;c=a.effect}if(f.isFunction(a)){d=a;b=null;a={}}if(typeof a=="number"||f.fx.speeds[a]){d=b;b=a;a={}}if(f.isFunction(b)){d=b;b=null}a=a||{};b=b||a.duration;b=f.fx.off?0:typeof b=="number"?b:b in f.fx.speeds?f.fx.speeds[b]:f.fx.speeds._default;d=d||a.complete;return[c,a,b,d]}function m(c){if(!c||typeof c==="number"||f.fx.speeds[c])return true;if(typeof c==="string"&&!f.effects[c])return true;return false}f.effects={};f.each(["backgroundColor","borderBottomColor","borderLeftColor","borderRightColor",
|
575 |
-
"borderTopColor","borderColor","color","outlineColor"],function(c,a){f.fx.step[a]=function(b){if(!b.colorInit){b.start=s(b.elem,a);b.end=n(b.end);b.colorInit=true}b.elem.style[a]="rgb("+Math.max(Math.min(parseInt(b.pos*(b.end[0]-b.start[0])+b.start[0],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[1]-b.start[1])+b.start[1],10),255),0)+","+Math.max(Math.min(parseInt(b.pos*(b.end[2]-b.start[2])+b.start[2],10),255),0)+")"}});var o={aqua:[0,255,255],azure:[240,255,255],beige:[245,245,220],black:[0,
|
576 |
-
0,0],blue:[0,0,255],brown:[165,42,42],cyan:[0,255,255],darkblue:[0,0,139],darkcyan:[0,139,139],darkgrey:[169,169,169],darkgreen:[0,100,0],darkkhaki:[189,183,107],darkmagenta:[139,0,139],darkolivegreen:[85,107,47],darkorange:[255,140,0],darkorchid:[153,50,204],darkred:[139,0,0],darksalmon:[233,150,122],darkviolet:[148,0,211],fuchsia:[255,0,255],gold:[255,215,0],green:[0,128,0],indigo:[75,0,130],khaki:[240,230,140],lightblue:[173,216,230],lightcyan:[224,255,255],lightgreen:[144,238,144],lightgrey:[211,
|
577 |
-
211,211],lightpink:[255,182,193],lightyellow:[255,255,224],lime:[0,255,0],magenta:[255,0,255],maroon:[128,0,0],navy:[0,0,128],olive:[128,128,0],orange:[255,165,0],pink:[255,192,203],purple:[128,0,128],violet:[128,0,128],red:[255,0,0],silver:[192,192,192],white:[255,255,255],yellow:[255,255,0],transparent:[255,255,255]},r=["add","remove","toggle"],t={border:1,borderBottom:1,borderColor:1,borderLeft:1,borderRight:1,borderTop:1,borderWidth:1,margin:1,padding:1};f.effects.animateClass=function(c,a,b,
|
578 |
-
d){if(f.isFunction(b)){d=b;b=null}return this.queue("fx",function(){var e=f(this),g=e.attr("style")||" ",h=q(p.call(this)),l,v=e.attr("className");f.each(r,function(w,i){c[i]&&e[i+"Class"](c[i])});l=q(p.call(this));e.attr("className",v);e.animate(u(h,l),a,b,function(){f.each(r,function(w,i){c[i]&&e[i+"Class"](c[i])});if(typeof e.attr("style")=="object"){e.attr("style").cssText="";e.attr("style").cssText=g}else e.attr("style",g);d&&d.apply(this,arguments)});h=f.queue(this);l=h.splice(h.length-1,1)[0];
|
579 |
-
h.splice(1,0,l);f.dequeue(this)})};f.fn.extend({_addClass:f.fn.addClass,addClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{add:c},a,b,d]):this._addClass(c)},_removeClass:f.fn.removeClass,removeClass:function(c,a,b,d){return a?f.effects.animateClass.apply(this,[{remove:c},a,b,d]):this._removeClass(c)},_toggleClass:f.fn.toggleClass,toggleClass:function(c,a,b,d,e){return typeof a=="boolean"||a===j?b?f.effects.animateClass.apply(this,[a?{add:c}:{remove:c},b,d,e]):this._toggleClass(c,
|
580 |
-
a):f.effects.animateClass.apply(this,[{toggle:c},a,b,d])},switchClass:function(c,a,b,d,e){return f.effects.animateClass.apply(this,[{add:a,remove:c},b,d,e])}});f.extend(f.effects,{version:"1.8.9",save:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.data("ec.storage."+a[b],c[0].style[a[b]])},restore:function(c,a){for(var b=0;b<a.length;b++)a[b]!==null&&c.css(a[b],c.data("ec.storage."+a[b]))},setMode:function(c,a){if(a=="toggle")a=c.is(":hidden")?"show":"hide";return a},getBaseline:function(c,
|
581 |
-
a){var b;switch(c[0]){case "top":b=0;break;case "middle":b=0.5;break;case "bottom":b=1;break;default:b=c[0]/a.height}switch(c[1]){case "left":c=0;break;case "center":c=0.5;break;case "right":c=1;break;default:c=c[1]/a.width}return{x:c,y:b}},createWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent();var a={width:c.outerWidth(true),height:c.outerHeight(true),"float":c.css("float")},b=f("<div></div>").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",
|
582 |
-
border:"none",margin:0,padding:0});c.wrap(b);b=c.parent();if(c.css("position")=="static"){b.css({position:"relative"});c.css({position:"relative"})}else{f.extend(a,{position:c.css("position"),zIndex:c.css("z-index")});f.each(["top","left","bottom","right"],function(d,e){a[e]=c.css(e);if(isNaN(parseInt(a[e],10)))a[e]="auto"});c.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})}return b.css(a).show()},removeWrapper:function(c){if(c.parent().is(".ui-effects-wrapper"))return c.parent().replaceWith(c);
|
583 |
-
return c},setTransition:function(c,a,b,d){d=d||{};f.each(a,function(e,g){unit=c.cssUnit(g);if(unit[0]>0)d[g]=unit[0]*b+unit[1]});return d}});f.fn.extend({effect:function(c){var a=k.apply(this,arguments),b={options:a[1],duration:a[2],callback:a[3]};a=b.options.mode;var d=f.effects[c];if(f.fx.off||!d)return a?this[a](b.duration,b.callback):this.each(function(){b.callback&&b.callback.call(this)});return d.call(this,b)},_show:f.fn.show,show:function(c){if(m(c))return this._show.apply(this,arguments);
|
584 |
-
else{var a=k.apply(this,arguments);a[1].mode="show";return this.effect.apply(this,a)}},_hide:f.fn.hide,hide:function(c){if(m(c))return this._hide.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="hide";return this.effect.apply(this,a)}},__toggle:f.fn.toggle,toggle:function(c){if(m(c)||typeof c==="boolean"||f.isFunction(c))return this.__toggle.apply(this,arguments);else{var a=k.apply(this,arguments);a[1].mode="toggle";return this.effect.apply(this,a)}},cssUnit:function(c){var a=this.css(c),
|
585 |
-
b=[];f.each(["em","px","%","pt"],function(d,e){if(a.indexOf(e)>0)b=[parseFloat(a),e]});return b}});f.easing.jswing=f.easing.swing;f.extend(f.easing,{def:"easeOutQuad",s
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|