XCloner – Backup and Restore - Version 3.1.0

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 Icon 128x128 XCloner – Backup and Restore
Version 3.1.0
Comparing to
See all releases

Code changes from version 3.0.1 to 3.1.0

Files changed (44) hide show
  1. admin.cloner.html.php +336 -294
  2. admin.cloner.php +66 -82
  3. admin.xcloner-backupandrestore.php +0 -5
  4. admin.xcloner.php +0 -10
  5. administrator/.htaccess +2 -0
  6. administrator/backups/.htaccess +2 -0
  7. browser/files_inpage.php +1 -3
  8. browser/files_xml.php +8 -21
  9. browser/xmlhttp.js +7 -7
  10. classes/.htaccess +2 -0
  11. classes/DropboxClient.php +659 -0
  12. classes/OAuthSimple.php +532 -0
  13. classes/fileRecursion.php +7 -1
  14. classes/mysqlBackup.class.php +16 -24
  15. classes/phpseclib/Crypt/AES.php +594 -0
  16. classes/phpseclib/Crypt/DES.php +1245 -0
  17. classes/phpseclib/Crypt/Hash.php +824 -0
  18. classes/phpseclib/Crypt/RC4.php +505 -0
  19. classes/phpseclib/Crypt/RSA.php +2356 -0
  20. classes/phpseclib/Crypt/Random.php +133 -0
  21. classes/phpseclib/Crypt/Rijndael.php +1424 -0
  22. classes/phpseclib/Crypt/TripleDES.php +1009 -0
  23. classes/phpseclib/Math/BigInteger.php +3551 -0
  24. classes/phpseclib/Net/SFTP.php +1609 -0
  25. classes/phpseclib/Net/SSH1.php +1408 -0
  26. classes/phpseclib/Net/SSH2.php +2660 -0
  27. classes/phpseclib/PHP/Compat/Function/array_fill.php +41 -0
  28. classes/phpseclib/PHP/Compat/Function/bcpowmod.php +66 -0
  29. classes/phpseclib/PHP/Compat/Function/str_split.php +59 -0
  30. cloner.config.php +20 -21
  31. cloner.cron.php +281 -196
  32. cloner.functions.php +94 -66
  33. common.php +29 -19
  34. configs/.htaccess +2 -0
  35. configs/test.php +0 -53
  36. css/main.css +1 -1
  37. index.html +0 -0
  38. index.php +0 -3
  39. index2.php +0 -3
  40. install.xcloner.php +0 -25
  41. javascript/backup.js +45 -45
  42. javascript/dtree.js +14 -14
  43. javascript/jquery-1.4.4.min.js +0 -167
  44. 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
- <html lang="en">
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">&nbsp;
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,'&nbsp;<?php echo LM_MENU_CLONER;?>','index2.php?option=com_cloner','','','images/logo.gif');
151
 
152
- d.add(800,0,'&nbsp;<?php echo LM_MENU_ADMINISTRATION;?>','','','','images/actions.gif','images/actions.gif');
153
 
154
- d.add(801,800,'&nbsp;<?php echo LM_MENU_CONFIGURATION;?>','index2.php?option=com_cloner&task=config','','','images/gen_settings.png');
155
- d.add(802,800,'&nbsp;<?php echo LM_MENU_CRON;?>','index2.php?option=com_cloner&task=cron','','','images/templatessm.png');
156
- d.add(803,800,'&nbsp;<?php echo LM_MENU_LANG;?>','index2.php?option=com_cloner&task=lang','','','images/lang.png');
157
 
158
 
159
- d.add(840,0,'&nbsp;<?php echo LM_MENU_ACTIONS;?>','','','','images/actions.gif','images/actions.gif');
160
- d.add(841,840,'&nbsp;<?php echo LM_MENU_View_backups;?>','index2.php?option=com_cloner&task=view','','','images/editionssm.png');
161
- d.add(842,840,'&nbsp;<?php echo LM_MENU_Generate_backup;?>','index2.php?option=com_cloner&task=confirm','','','images/wizardsm.png');
162
- d.add(843,840,'&nbsp;<?php echo LM_MENU_Restore_backup;?>','index2.php?option=com_cloner&task=restore','','','images/wizardsm_restore.gif');
163
 
164
- d.add(830,0,'&nbsp;<?php echo LM_MENU_SUPPORT;?>','','','','images/support.png','images/support.png');
165
- d.add(831,830,'&nbsp;<?php echo LM_MENU_FORUM;?>','http://www.xcloner.com/support/forums/','','_blank','images/forum.png','images/forum.png');
166
- d.add(832,830,'&nbsp;<?php echo LM_MENU_WEBSITE;?>','http://www.xcloner.com','','_blank','images/website.png','images/website.png');
167
 
168
 
169
 
170
- d.add(820,0,'&nbsp;<?php echo LM_MENU_Documentation;?>','','','','images/help.png','images/help.png');
171
- d.add(821,820,'&nbsp;<?php echo LM_MENU_ABOUT;?>','index2.php?option=com_cloner&task=about','','','images/about.png','images/about.png');
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 ('&amp;cb=' + m3_r);
190
- if (document.MAX_used != ',') document.write ("&amp;exclude=" + document.MAX_used);
191
- document.write (document.charset ? '&amp;charset='+document.charset : (document.characterSet ? '&amp;charset='+document.characterSet : ''));
192
- document.write ("&amp;loc=" + escape(window.location));
193
- if (document.referrer) document.write ("&amp;referer=" + escape(document.referrer));
194
- if (document.context) document.write ("&context=" + escape(document.context));
195
- if (document.mmm_fo) document.write ("&amp;mmm_fo=1");
196
- document.write ("'><\/scr"+"ipt>");
197
- //]]>--></script><noscript><a href='http://www.xcloner.com/ads/www/delivery/ck.php?n=a6255e1e&amp;cb=1675675575' target='_blank'><img src='http://www.xcloner.com/ads/www/delivery/avw.php?campaignid=3&amp;cb=1675675575&amp;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> $( "#toolbar" ).show(); </script>
223
- </body></html>
 
 
 
 
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 = "index2.php?option=com_cloner&lines=" . $perm_lines . "&task=refresh&backup=$backupFile&excl_manual=$excl_manual";
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
- $(document).ready(function() {
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
- $("#progressbar").progressbar({ value: 0 });
269
 
270
- $.ajaxSetup({
271
  "error":function(request, status, error) {
272
  //reset state here;
273
- $("#error").show();
274
- $("#errorText").append(status+" -- "+error);
275
- $("#errorText").append("<br /><br />JSON url: "+globalUrl);
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
- $.getJSON(url, function(json) {
295
 
296
  if(!json){
297
- $("#error").show();
298
- $("#errorText").text(url);
299
  }
300
 
301
  if(json.dumpsize && !json.endDump){
302
- $("#mysqlProcess").append(" ("+getSize(json.dumpsize, 1024*1024)+" MB) <br />");
303
  }
304
 
305
  if(json.newDump){
306
  count++;
307
- //$("#mysqlProcess").append(appendIcon("arrowthick-1-e"));
308
  if(json.databaseName!="")
309
- $("#mysqlProcess").append("<b>["+json.databaseName+"]</b> <span id='db"+count+"'></span> tables ");
310
  counter = parseInt(json.startAtLine);
311
 
312
  }else{
313
- $("#db"+count).text(json.startAtLine - counter);
314
  }
315
 
316
  if(!parseInt(json.finished)){
317
  //get next records
318
 
319
- $("#db"+count).text(json.startAtLine - counter);
320
 
321
- 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;
322
  xclonerRecurseMYSQL(recurseUrl);
323
 
324
  }
325
  else{
326
 
327
- $("#fileSystem").show();
328
- var recurseUrl="index2.php?task=recurse_files&mode=start&nohtml=1";
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
- $("#result").hide();
340
 
341
  globalUrl = url;
342
  step = "r2";
343
 
344
- $.getJSON(url, function(json) {
345
 
346
  if(!json){
347
- $("#error").show();
348
- $("#errorText").text(url);
349
  }
350
 
351
  if(!parseInt(json.finished)){
352
 
353
- $("#recurseStatus").text(json.tfiles);
354
 
355
- var recurseUrl = "index2.php?task=recurse_files&mode="+json.mode+"&nohtml=1";
356
  xclonerRecurseJSON(recurseUrl);
357
 
358
  }
359
  else{
360
  var size = parseFloat(json.size)/(1024*1024);
361
- $("#recurseStatus").text(" done! (Estimated size:"+size.toFixed(2)+"MB) in "+json.tfiles+" files");
362
- $("#result").show();
363
 
364
  if(json.overlimit.length > 0){
365
- $("#overlimit").show();
366
  for(var i=0; i < json.overlimit.length; i++){
367
 
368
- $("#overlimit").append("<span class='oversizedFile'></span>"+json.overlimit[i]+"<br />");
369
 
370
  }
371
  }
372
 
373
  //xclonerGetJSON("<?php echo $urlReturn;?>");
374
- returnUrl = "index2.php?option=com_cloner&lines="+json.tfiles+"&task=refresh&backup=<?php echo $backupFile; ?>&excl_manual=";
375
  xclonerGetJSON(returnUrl);
376
 
377
  }
@@ -385,19 +339,19 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
385
  globalUrl = url;
386
  step = "r3";
387
 
388
- $.getJSON(url, function(json) {
389
 
390
  if(!json){
391
- $("#error").show();
392
- $("#errorText").append(url);
393
  }
394
 
395
  var percent = parseInt(json.percent);
396
- $("#progressbar").progressbar({ value: percent });
397
- $("#backupSize").text(getSize(json.backupSize, 1024*1024));
398
- $("#nFiles").text(json.startf);
399
- $("#percent").text(json.percent);
400
- $("#backupName").text(json.backup);
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 = "index2.php?option="+json.option+"&task="+json.task+"&json="+json.json+"&startf="+json.startf+"&lines="+json.lines+"&backup="+json.backup+"&excl_manual="+json.excl_manual;
412
  xclonerGetJSON(url);
413
  }else{
414
 
415
  //all done
416
- url = "index2.php?task=cleanup&nohtml=1";
417
- $.getJSON(url, function(json) {
418
  });
419
 
420
- $("#complete").show();
421
- $("#nFiles").text(json.lines);
422
  if(parts > 0){
423
- $("#backupParts").show();
424
- $("#backupPartsNr").text(parts);
425
  }
426
- $("#backupFiles").text(json.lines);
427
- $("#backupSizeComplete").append(getSize(completeSize+parseInt(json.backupSize), 1024*1024));
428
- $("#backupNameC").text(json.backup);
429
- $( "#dialog:ui-dialog" ).dialog( "destroy" );
430
- $( "#dialog-message" ).dialog({
431
  modal: true,
432
  width: 600,
433
  buttons: {
434
  Close: function() {
435
- $( this ).dialog( "close" );
436
  }
437
  }
438
  });
@@ -445,9 +399,9 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
445
 
446
  //Main program here
447
 
448
- $("#retry").click(function(){
449
- $("#error").hide();
450
- $("#errorText").empty();
451
  if(step == "r1"){
452
  xclonerRecurseMYSQL(globalUrl);
453
  }
@@ -460,15 +414,15 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
460
  }
461
  });
462
 
463
- $("#result").hide();
464
- $("#fileSystem").hide();
465
 
466
  if(dbbackup){
467
- recurseUrl = "index2.php?task=recurse_database&nohtml=1&dbbackup_comp=<?php echo $_REQUEST['dbbackup_comp']?>&dbbackup_drop=<?php echo $_REQUEST['dbbackup_drop']?>";
468
  xclonerRecurseMYSQL(recurseUrl);
469
  }else{
470
- $("#fileSystem").show();
471
- var recurseUrl="index2.php?task=recurse_files&mode=start&nohtml=1";
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="index2.php" name="adminForm" method="post">
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="index2.php" method="post" name="adminForm">
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="index2.php?option=com_cloner&amp;task=config">
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="index2.php?option=com_cloner&amp;task=view">
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="index2.php?option=com_cloner&amp;task=confirm">
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="index2.php?option=com_cloner&amp;task=about">
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 = HTML_cloner::path_check($_CONFIG[backup_start_path]);
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 = HTML_cloner::path_check($_CONFIG[backup_store_path]);
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 = HTML_cloner::path_check($_CONFIG[temp_dir]);
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
- <div class="status">
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
- $(function() {
751
- $( "button, submit:input", ".loginform" ).button({
752
  icons: {
753
  primary: "ui-icon-locked"
754
  }
755
- }).next()
756
- .button({
 
 
 
 
 
757
  icons: {
758
  primary: "ui-icon-trash"
759
  }
760
  })
761
- .click(function() {
762
- $("#adminForm")[0].reset();
763
- return false;
764
- });
765
-
766
 
767
  });
768
  </script>
769
 
770
 
771
  <div class="loginform">
772
- <form action="index2.php" method="post" name="adminForm" id="adminForm">
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>&nbsp;</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
- $(function() {
809
- $( "#tabs" ).tabs();
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?config=myconfig.php", only use 'links' or 'lynx' options to run the cronjob
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="index2.php" method="post" name="adminForm">
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="index2.php" method="post" name="adminForm">
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="index2.php" method="post" name="adminForm">
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
- $(function() {
980
- $( "#toggle" ).button();
981
- $( "#toggle" ).click(function() { checkJAll(<?php echo count( $lang_arr ); ?>, "toggle", "cb"); });
982
- $( "#checklist" ).buttonset();
983
  });
984
  </script>
985
 
986
- <form action="index2.php" method="post" name="adminForm">
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="index2.php?option=<?php echo $option;?>&task=edit_lang&langx=<?php echo $lang_arr[$i];?>"><?php echo ucfirst($lang_arr[$i])?>
1012
  </td>
1013
  </tr>
1014
  <?php
@@ -1032,15 +988,49 @@ function showBackups( &$files, &$sizes, $path, $option ) {
1032
 
1033
  ?>
1034
 
1035
- <script>
1036
- $(function() {
1037
- $( "#toggle" ).button();
1038
- $( "#toggle" ).click(function() { checkJAll(<?php echo (count( $files )); ?>, "toggle", "cb"); });
1039
- $( "#checklist" ).buttonset();
1040
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1041
  </script>
 
 
 
 
 
 
 
 
1042
  <div id="checklist">
1043
- <form action="index2.php" method="post" name="adminForm">
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 = "index2.php?option=com_cloner&task=download&file=".'/'.urlencode($files[$i]);
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='index2.php' method='POST'>
1109
 
1110
  <script>
1111
- $(function() {
1112
- $( "#tabs" ).tabs();
1113
  });
1114
 
1115
- $(function() {
1116
- $( "#radiog1" ).buttonset();
1117
- $( "#radiog2" ).buttonset();
1118
- $( "#radiog3" ).buttonset();
1119
- $( "#radiog4" ).buttonset();
1120
- $( "#radio" ).buttonset();
1121
- $( "#radiom" ).buttonset();
1122
- $( "#radiob" ).buttonset();
1123
- $( "#radioftp" ).buttonset();
1124
- $( "#radioftps" ).buttonset();
1125
- $( "#radiodebug" ).buttonset();
1126
- $( "#radiorefresh" ).buttonset();
1127
- $( "#checktar" ).button();
1128
- $( "#cron_file_delete_act" ).button();
1129
- $( "#cron_sql_drop" ).button();
1130
- $( "#cron_amazon_active" ).button();
1131
- $( "#cron_ftp_delb" ).button();
1132
- $( "#checkmysqldump" ).button();
 
 
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
- <li><a href="#tabs-3"><?php echo LM_TAB_AUTH;?></a></li>
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
- <tr><th colspan='2'>
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
- <tr>
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='1'>
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
- <div>
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
- $tabs->startTab(LM_TAB_AUTH,"3");
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
- $(function() {
1478
- $( "#slider" ).slider({
1479
  value:parseInt(<?php echo $_CONFIG[backup_refresh_number];?>),
1480
  min: 10,
1481
  max: 1000,
1482
  step: 10,
1483
  slide: function( event, ui ) {
1484
- $( "#backup_refresh_number" ).val( ui.value );
1485
  }
1486
  });
1487
- $( "#backup_refresh_number" ).val( $( "#slider" ).slider( "value" ) );
1488
  });
1489
- $(function() {
1490
- $( "#sliderRPS" ).slider({
1491
  value:parseInt(<?php echo $_CONFIG[recordsPerSession];?>),
1492
  min: 100,
1493
  max: 100000,
1494
  step: 100,
1495
  slide: function( event, ui ) {
1496
- $( "#recordsPerSession" ).val( ui.value );
1497
  }
1498
  });
1499
- $( "#recordsPerSession" ).val( $( "#sliderRPS" ).slider( "value" ) );
1500
  });
1501
- $(function() {
1502
- $( "#sliderEFZ" ).slider({
1503
  value:parseInt(<?php echo $_CONFIG[excludeFilesSize];?>),
1504
  min: -1,
1505
  max: 10240,
1506
  step: 1,
1507
  slide: function( event, ui ) {
1508
- $( "#excludeFilesSize" ).val( ui.value );
1509
  }
1510
  });
1511
- $( "#excludeFilesSize" ).val( $( "#sliderEFZ" ).slider( "value" ) );
1512
  });
1513
 
1514
- $(function() {
1515
- $( "#sliderSBS" ).slider({
1516
  value:parseInt(<?php echo $_CONFIG[splitBackupSize];?>),
1517
  min: -1,
1518
  max: 10000,
1519
  step: 1,
1520
  slide: function( event, ui ) {
1521
- $( "#splitBackupSize" ).val( ui.value );
1522
  }
1523
  });
1524
- $( "#splitBackupSize" ).val( $( "#sliderSBS" ).slider( "value" ) );
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 = @opendir($_CONFIG['multiple_config_dir'])) {
1629
 
1630
  while (false !== ($file = readdir($handle))) {
1631
  if( ($file!=".") && ($file!="..") &&($file!="") && (strstr($file, '.php'))){
1632
- $fcron = "cloner.cron.php?config=$file";
1633
 
1634
  echo "<b>$fcron</b>";
1635
 
1636
  echo " - <a href='$fcron' target='_blank'>execute cron</a>";
1637
 
1638
- echo " | <a href='index2.php?option=com_cloner&task=cron_delete&fconfig=$file'>delete config</a>";
1639
 
1640
  echo "\n<br />";
1641
  }
@@ -1712,7 +1706,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
1712
  </tr>
1713
 
1714
 
1715
- <tr>
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 = @mysql_query("SHOW databases");
1877
- while($row = @mysql_fetch_array($query)){
1878
 
1879
  $table = $row[0];
1880
 
@@ -1906,17 +1953,17 @@ function showBackups( &$files, &$sizes, $path, $option ) {
1906
  <div><p>
1907
 
1908
  <script>
1909
- $(function() {
1910
- $( "#slider2" ).slider({
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
- $( "#cron_file_delete" ).val( ui.value );
1917
  }
1918
  });
1919
- $( "#cron_file_delete" ).val( $( "#slider2" ).slider( "value" ) );
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="index2.php" method="GET" name="adminForm">
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="index2.php" method="post" name="adminForm">
2273
  <?php
2274
  $tabs = new mosTabs(1);
2275
  ?>
2276
 
2277
  <script>
2278
- $(function() {
2279
- $( "#tabs" ).tabs().find( ".ui-tabs-nav" ).sortable({ axis: "x" });
2280
- $( "#radio_dbbackup" ).buttonset();
2281
- $( "#radio_dbbackup1" ).button( { icons: {primary:'ui-icon-bullet'} } );
2282
- $( "#radio_dbbackup2" ).button( { icons: {primary:'ui-icon-bullet'} } );
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 = mysql_query("SHOW tables");
2336
- while($row = mysql_fetch_array($query)){
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 = mysql_query("SHOW databases");
2357
 
2358
- while($row = mysql_fetch_array($query)){
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>&nbsp;</strong></td><td>&nbsp;</td>
2479
  </tr>
2480
  </table>
2481
- <form action="index2.php" name="adminForm" method="post">
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
- $(function() {
2514
- $( "#tabs" ).tabs();
2515
  });
2516
  </script>
2517
 
@@ -2526,7 +2568,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
2526
  </div>
2527
  </div>
2528
  </div>
2529
- <form action="index2.php" name="adminForm" method="post">
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
- $(function() {
2545
- $( "#tabs" ).tabs();
2546
  });
2547
  </script>
2548
 
@@ -2560,7 +2602,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
2560
  </table>
2561
  </p></div>
2562
  </div>
2563
- <form action="index2.php" name="adminForm" method="post">
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
- $(function() {
2577
- $( "#tabs" ).tabs();
2578
  });
2579
  </script>
2580
 
@@ -2592,7 +2634,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
2592
  </table>
2593
  </p></div>
2594
  </div>
2595
- <form action="index2.php" name="adminForm" method="post">
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="index2.php" method="post" name="adminForm">
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="index2.php" name="adminForm" method="post">
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">&nbsp;
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,'&nbsp;<?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,'&nbsp;<?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,'&nbsp;<?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,'&nbsp;<?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,'&nbsp;<?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,'&nbsp;<?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,'&nbsp;<?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,'&nbsp;<?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,'&nbsp;<?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,'&nbsp;<?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,'&nbsp;<?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,'&nbsp;<?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,'&nbsp;<?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,'&nbsp;<?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&amp;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&amp;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&amp;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&amp;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>&nbsp;</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>&nbsp;</strong></td><td>&nbsp;</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
- session_start();
25
- @set_time_limit("3600");
26
- @error_reporting(E_ALL ^ E_NOTICE);
27
 
28
- define("_VALID_MOS", 1);
 
29
 
30
- //load configuration
31
- $config_file = "cloner.config.php";
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
- $option = "xcloner";
39
 
40
- //Doing some basic authentification
41
- if ((!isset($_SESSION['clone'])) && ($task != 'dologin')) {
42
- $task = 'login';
 
43
 
44
- HTML_cloner::header();
45
 
46
- HTML_cloner::Login();
 
 
 
47
 
48
- HTML_cloner::footer();
49
 
50
- exit;
51
- } elseif ($task == 'dologin') {
52
- if (($_REQUEST['username'] == $_CONFIG['jcuser']) && (md5($_REQUEST['password']) == $_CONFIG['jcpass'])) {
53
- if (function_exists('session_register')) {
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
- if(!$_REQUEST['nohtml'])
79
- if (($task != 'download') and (($_REQUEST['task']!="refresh") or (!$_CONFIG['refresh_mode'])))
80
- HTML_cloner::header();
81
-
82
- //########## SETTING THE GLOBALS VARIABLES #########################
83
 
84
- $GLOBALS['joomla_compatible'] = $joomla_compatible;
85
 
86
- $GLOBALS['_CONFIG'] = $_CONFIG;
87
 
88
- $GLOBALS['clonerPath'] = $clonerPath;
89
 
90
- $GLOBALS['baDownloadPath'] = $baDownloadPath;
91
 
92
- $GLOBALS['config_file'] = $config_file;
93
 
94
- $GLOBALS['lang_array'] = $lang_array;
95
 
96
- openXLog();
97
 
98
- // process the workflow selection
99
- switch ($task) {
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('index2.php?option=' . $option . "&task=lang");
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
- HTML_cloner::Cron();
167
  break;
168
  case 'about':
169
  case 'credits':
170
  showHelp($option);
171
  break;
172
  case 'restore':
173
- HTML_cloner::Restore($option);
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('index2.php?option=' . $option . "&task=config", $_REQUEST['fconfig'] . $msg);
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('index2.php?option=' . $option);
196
  break;
197
  case 'config':
198
  config($option);
199
  break;
200
  case 'rename_cancel':
201
- mosRedirect('index2.php?option=' . $option . "&task=view");
202
  break;
203
  case 'show':
204
  case 'view':
@@ -210,11 +192,13 @@
210
  default:
211
  fdefault();
212
  break;
213
- }
 
 
214
 
215
- closeXLog();
216
- if(!$_REQUEST['nohtml'])
217
- HTML_cloner::footer();
 
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
- @ini_set("error_reporting", "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
- define("_VALID_MOS", 1);
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
- ### testing the authenticity of access
28
- if($_COOKIE["auth_clone"] != 1){
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("browser/files_xml.php")){
40
  targetDiv.className="searching";
41
  targetDiv.innerHTML="";
42
  }
@@ -110,24 +110,24 @@ function useXML(xmlInfo){
110
  else
111
  loc1 = loc;
112
 
113
- var newloc1="browser/files_xml.php?dir=" + loc ;
114
 
115
  var stringHTML="<p><b>" + loc1 +"</b> <br /><br /></p>";
116
 
117
  if(loc.indexOf("/")!=-1){
118
- var newfile="browser/files_xml.php?dir=" + loc.slice(0, loc.lastIndexOf("/"));
119
  stringHTML=stringHTML+"<p><a href=\"#\" onclick=\"loadXMLDoc('" + newfile +"')\">[Up a level]</a> <a href='#' onclick=\"loadXMLDoc('" + newloc1 +"&amp;act=checkall')\" >[check all]</a> <a href='#' onclick=\"loadXMLDoc('" + newloc1 +"&amp;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="browser/files_xml.php?dir=" + loc ;
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 +"&amp;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="browser/files_xml.php?dir=" + loc + "/" + node.firstChild.nodeValue;
143
- stringHTML=stringHTML+"<li class=\"folder\"><img src='browser/folder.gif' border='0'><input type=checkbox "+node.getAttribute('check')+" onclick=\"loadXMLDoc('" + newloc +"&amp;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 +"&amp;act=checkall')\" >[check all]</a> <a href='#' onclick=\"loadXMLDoc('" + newloc1 +"&amp;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 +"&amp;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 +"&amp;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 2011 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,16 +105,10 @@ class DB{
105
  */
106
  public function connect(){
107
 
108
- self::$link = mysql_connect(self::$dbHostname, self::$dbUsername, self::$dbPassword);
109
- if (!self::$link) {
110
- self::error('Could not connect: ' . mysql_error());
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
- mysql_close(self::$link);
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
- mysql_set_charset('utf8', self::$link);
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 = mysql_query($query.";", self::$link);
162
  self::error($query, 1);
163
 
164
  if (!$result) {
165
- self::error('Invalid query: ' . mysql_error());
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 = mysql_fetch_array($result)){
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 = mysql_fetch_row($result);
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 = mysql_fetch_array($result, MYSQL_ASSOC)){
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 = mysql_escape_string($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 = mysql_fetch_row($result);
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 = mysql_fetch_array($result)){
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 2007
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
- require_once( 'cloner.config.php' );
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
- if($_REQUEST['config'] == ""){
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
- @require_once( './cloner.config.php' );
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
- #logxx("Reading the file structure");
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
- // turn passive mode on
238
- @ftp_pasv($conn_id, true);
239
- $mode = "Passive";
240
- }
241
- else
242
- {
243
- // turn passive mode off
244
- @ftp_pasv($conn_id, false);
245
- $mode = "Active";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
246
  }
247
- echo "Connected to $connect <b>$_CONFIG[cron_ftp_server] Mode: $mode</b><br />";
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
- $s3 = new S3($_CONFIG['cron_amazon_awsAccessKey'], $_CONFIG['cron_amazon_awsSecretKey']);
 
 
 
313
 
314
- logxx("AMAZON S3: Starting communication with the Amazon S3 server...");
 
 
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: \"Cronlog XCloner\" <nobody@noreply.com>\n";
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 "<center><font color='red' size='4'>$message</font></center>";
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::_FDefault();
 
127
  }
128
 
129
  function config($option)
@@ -132,31 +135,32 @@
132
 
133
 
134
  if (@$_REQUEST['action'] == 'save') {
135
- //print_r($_REQUEST);exit;
 
 
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
- if ($fp = @fopen($config_file, 'w')) {
 
 
 
 
 
 
 
 
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::Config($option);
 
290
  }
291
 
292
  //## JoomlaCloner Language Manager
@@ -312,7 +329,8 @@
312
  mosRedirect('index2.php?option=' . $option . "&task=lang", $msg);
313
  }
314
 
315
- HTML_cloner::Translator($option, $lang_array);
 
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
- HTML_cloner::Translator_Add($option);
344
  }
345
  function translator_edit($option, $task)
346
  {
@@ -422,14 +440,15 @@
422
 
423
 
424
  if ($lang == 'english') {
425
- HTML_cloner::Translator_Edit_DEFAULT($option, $content, $file, $lang);
 
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
- HTML_cloner::Translator_Edit($option, $data, $def_data, $file, $lang);
433
  }
434
  }
435
 
@@ -644,7 +663,8 @@
644
  getBackupFiles($d_arr, $f_arr, $s_arr, $d, $f);
645
 
646
  // load presentation layer
647
- HTML_cloner::showBackups($f_arr, $s_arr, $_CONFIG['clonerPath'], $option);
 
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
- HTML_cloner::TransferForm($option, $files_out);
 
 
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
- HTML_Cloner::rename($files, $option);
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
- HTML_cloner::confirmBackups($d_arr, $ds_arr, $_CONFIG['clonerPath'], $option);
1028
- else
 
1029
  return $d_arr;
1030
  }
1031
 
@@ -1087,7 +1110,7 @@ function smartReadFile($location, $filename, $mimeType='application/octet-stream
1087
  }
1088
 
1089
 
1090
- $url = "index2.php?option=com_cloner&task=refresh&json=$json&startf=$endf&lines=$lines&backup=$backup_filename&excl_manual=" . $_REQUEST['excl_manual'];
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
- mysql_query("USE $database_name");
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
- mysql_query("USE " . $_CONFIG['mysql_database']);
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
- HTML_cloner::goRefreshHtml($filename, $perm_lines, $excl_manual);
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
- HTML_cloner::goRefreshHtml($filename, $perm_lines, $excl_manual);
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
- HTML_cloner::generateBackup($filename1, $archiveSize, $originalSize, $mdir, $f, $databaseResult, $option);
 
1682
  } else {
1683
 
1684
-
1685
- logxx(HTML_cloner::generateBackup_text($filename1, $archiveSize, $originalSize, $mdir, $f, $databaseResult, $option));
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::showHelp($option);
 
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 = mysql_query("SHOW tables");
1920
- while ($row = mysql_fetch_array($query)) {
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
- mysql_query("SET SQL_QUOTE_SHOW_CREATE=1;");
1973
- mysql_query("SET sql_mode = 0;");
1974
 
1975
  if ($_REQUEST['dbbackup_comp']) {
1976
- mysql_query("SET sql_mode=" . $_REQUEST['dbbackup_comp'] . ";");
1977
  }
1978
 
1979
 
1980
  /* Store the "Create Tables" SQL in variable $CreateTable[$tblval] */
1981
  if ($toBackUp != "data") {
1982
  foreach ($tables as $tblval) {
1983
- $query = mysql_query("SHOW CREATE table `$tblval`");
1984
- $row = mysql_fetch_array($query);
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 = mysql_query("SHOW FIELDS FROM `$tblval`");
1993
- while ($row = mysql_fetch_row($query)) {
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 = @mysql_query("SELECT * FROM `$tblval`");
2047
 
2048
- while ($row = @mysql_fetch_array($query, MYSQL_ASSOC)) {
2049
  $InsertDump = "INSERT INTO `$tblval` VALUES (";
2050
  $arr = $row;
2051
  foreach ($arr as $key => $value) {
2052
- $value = addslashes($value);
2053
- $value = str_replace("\n", '\r\n', $value);
2054
- $value = str_replace("\r", '', $value);
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
- $query = mysql_query("SELECT version()");
2122
- $row = mysql_fetch_array($query);
2123
- return $row[0];
 
 
 
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'] = realpath($_CONFIG['backup_path'])."/";
39
- $_CONFIG['backups_dir'] = realpath($_CONFIG['backup_path'])."/administrator/backups";
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
- border: solid 1px #d5d5d5;
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
- $(document).ready(function() {
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
- $("#progressbar").progressbar({ value: 0 });
10
 
11
- $.ajaxSetup({
12
  "error":function(request, status, error) {
13
  //reset state here;
14
- $("#error").show();
15
- $("#errorText").append(status+" -- "+error);
16
- $("#errorText").append("<br /><br />JSON url: "+globalUrl);
17
  }});
18
 
19
  function getSize(bytes, conv){
@@ -32,41 +32,41 @@ $(document).ready(function() {
32
  globalUrl = url;
33
  step = "r1";
34
 
35
- $.getJSON(url, function(json) {
36
 
37
  if(!json){
38
- $("#error").show();
39
- $("#errorText").text(url);
40
  }
41
 
42
  if(json.dumpsize && !json.endDump){
43
- $("#mysqlProcess").append(" ("+getSize(json.dumpsize, 1024*1024)+" MB) <br />");
44
  }
45
 
46
  if(json.newDump){
47
  count++;
48
- //$("#mysqlProcess").append(appendIcon("arrowthick-1-e"));
49
  if(json.databaseName!="")
50
- $("#mysqlProcess").append("<b>["+json.databaseName+"]</b> <span id='db"+count+"'></span> tables ");
51
  counter = parseInt(json.startAtLine);
52
 
53
  }else{
54
- $("#db"+count).text(json.startAtLine - counter);
55
  }
56
 
57
  if(!parseInt(json.finished)){
58
  //get next records
59
 
60
- $("#db"+count).text(json.startAtLine - counter);
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
- $("#fileSystem").show();
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
- $("#result").hide();
81
 
82
  globalUrl = url;
83
  step = "r2";
84
 
85
- $.getJSON(url, function(json) {
86
 
87
  if(!json){
88
- $("#error").show();
89
- $("#errorText").text(url);
90
  }
91
 
92
  if(!parseInt(json.finished)){
93
 
94
- $("#recurseStatus").text(json.tfiles);
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
- $("#recurseStatus").text(" done! (Estimated size:"+size.toFixed(2)+"MB) in "+json.tfiles+" files");
103
- $("#result").show();
104
- returnUrl = "index2.php?option=com_cloner&lines="+json.tfiles+"&task=refresh&backup="+backupFile+"&excl_manual=";
105
  xclonerGetJSON(returnUrl);
106
 
107
  }
@@ -115,35 +115,35 @@ $(document).ready(function() {
115
  globalUrl = url;
116
  step = "r3";
117
 
118
- $.getJSON(url, function(json) {
119
 
120
  if(!json){
121
- $("#error").show();
122
- $("#errorText").append(url);
123
  }
124
 
125
  var percent = parseInt(json.percent);
126
- $("#progressbar").progressbar({ value: percent });
127
- $("#backupSize").text(json.backupSize);
128
- $("#nFiles").text(json.startf);
129
- $("#percent").text(json.percent);
130
  if(!json.finished){
131
- var url = "index2.php?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
- $("#complete").show();
136
- $("#nFiles").text(json.lines);
137
- $("#backupFiles").text(json.lines);
138
- $("#backupSizeComplete").text(json.backupSize);
139
- $("#backupName").text(json.backup);
140
- $( "#dialog:ui-dialog" ).dialog( "destroy" );
141
- $( "#dialog-message" ).dialog({
142
  modal: true,
143
  width: 600,
144
  buttons: {
145
  Close: function() {
146
- $( this ).dialog( "close" );
147
  }
148
  }
149
  });
@@ -154,9 +154,9 @@ $(document).ready(function() {
154
 
155
  }
156
 
157
- $("#retry").click(function(){
158
- $("#error").hide();
159
- $("#errorText").empty();
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||"&#160;",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||"&#160;"));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&#8230;</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?"&#xa0;":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)?"&#xa0;":""));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)?"&#xa0;":"")+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