XCloner – Backup and Restore - Version 3.0.9

Version Description

  • addd dropbox support
Download this release

Release Info

Developer xcloner
Plugin Icon 128x128 XCloner – Backup and Restore
Version 3.0.9
Comparing to
See all releases

Code changes from version 3.0.5 to 3.0.9

Files changed (58) hide show
  1. admin.cloner.html.php +1641 -1071
  2. admin.cloner.php +222 -198
  3. admin.xcloner-backupandrestore.php +5 -0
  4. browser/files_inpage.php +10 -3
  5. browser/files_xml.php +21 -14
  6. browser/xmlhttp.js +5 -5
  7. classes/DropboxClient.php +659 -0
  8. classes/OAuthSimple.php +532 -0
  9. classes/S3.php +4 -1
  10. administrator/backups/.excl → classes/error.class.php +0 -0
  11. classes/fileRecursion.php +57 -8
  12. classes/index.html +0 -0
  13. classes/main.class.php +116 -0
  14. classes/mysqlBackup.class.php +488 -0
  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 +3 -0
  31. cloner.cron.php +229 -89
  32. cloner.functions.php +336 -155
  33. common.php +47 -17
  34. css/main.css +90 -6
  35. css/start/images/ui-bg_flat_55_999999_40x100.png +0 -0
  36. css/start/images/ui-bg_flat_75_aaaaaa_40x100.png +0 -0
  37. css/start/images/ui-bg_glass_45_0078ae_1x400.png +0 -0
  38. css/start/images/ui-bg_glass_55_f8da4e_1x400.png +0 -0
  39. css/start/images/ui-bg_glass_75_79c9ec_1x400.png +0 -0
  40. css/start/images/ui-bg_gloss-wave_45_e14f1c_500x100.png +0 -0
  41. css/start/images/ui-bg_gloss-wave_50_6eac2c_500x100.png +0 -0
  42. css/start/images/ui-bg_gloss-wave_75_2191c0_500x100.png +0 -0
  43. css/start/images/ui-bg_inset-hard_100_fcfdfd_1x100.png +0 -0
  44. css/start/images/ui-icons_0078ae_256x240.png +0 -0
  45. css/start/images/ui-icons_056b93_256x240.png +0 -0
  46. css/start/images/ui-icons_d8e7f3_256x240.png +0 -0
  47. css/start/images/ui-icons_e0fdff_256x240.png +0 -0
  48. css/start/images/ui-icons_f5e175_256x240.png +0 -0
  49. css/start/images/ui-icons_f7a50d_256x240.png +0 -0
  50. css/start/images/ui-icons_fcd113_256x240.png +0 -0
  51. css/{jquery-ui.css → start/jquery-ui-1.8.9.custom.css} +319 -316
  52. css/tabber.css +0 -109
  53. images/logo.gif +0 -0
  54. images/logo.png +0 -0
  55. images/{progress.gif → progressBarLong.gif} +0 -0
  56. install.xcloner.php +4 -12
  57. javascript/backup.js +172 -0
  58. javascript/jquery-ui-1.8.9.custom.min.js +516 -0
admin.cloner.html.php CHANGED
@@ -31,20 +31,20 @@ class mosTabs{
31
 
32
  function mosTabs($int){
33
 
34
- echo "<div class=\"tabber\">";
35
 
36
  }
37
 
38
  function startTab($name, $class){
39
 
40
- echo "<div class=\"tabbertab\" title=\"$name\">";
41
 
42
 
43
  }
44
 
45
  function endTab(){
46
 
47
- echo "</div>";
48
 
49
  }
50
 
@@ -63,8 +63,16 @@ class HTML_cloner {
63
 
64
  function header(){
65
 
66
- global $mosConfig_live_site, $task;
 
67
 
 
 
 
 
 
 
 
68
  ?>
69
  <html lang="en">
70
  <head>
@@ -72,16 +80,14 @@ function header(){
72
  <title>XCloner Backup and Restore</title>
73
  <META NAME="ROBOTS" CONTENT="NOINDEX, NOFOLLOW">
74
 
75
- <link rel="stylesheet" href="css/tabber.css" TYPE="text/css" MEDIA="screen">
76
  <link rel="styleSheet" href="css/dtree.css" type="text/css" />
77
  <link rel="styleSheet" href="css/main.css" type="text/css" />
78
- <link rel="styleSheet" href="css/jquery-ui.css" type="text/css" />
79
 
80
- <script type="text/javascript" src="javascript/tabber.js"></script>
81
  <script type="text/javascript" src="javascript/dtree.js"></script>
82
  <script type="text/javascript" src="javascript/main.js"></script>
83
  <script type="text/javascript" src="javascript/jquery-1.4.4.min.js"></script>
84
- <script type="text/javascript" src="javascript/jquery-ui.min.js"></script>
85
  <script type="text/javascript">
86
 
87
  /* Optional: Temporarily hide the "tabber" class so it does not "flash"
@@ -101,23 +107,31 @@ document.write('<style type="text/css">.tabber{display:none;}<\/style>');
101
 
102
  <tr><td align='center'>
103
 
104
- <table width='100%' border='1' bgcolor='white'>
 
105
  <tr>
106
- <td width='100%'>
107
- <table><tr><td>
108
- <img src="images/backup.png" align="middle">&nbsp;
109
- </td><td>
110
- <h2><?php echo LM_COM_TITLE.$_SERVER['HTTP_HOST']; ?></h2>
111
- <h1>Backup and Restore</h1>
112
- </td></tr></table>
113
- <td>
114
- <?php
115
- # Generating the buttons...
116
- require_once( "toolbar.cloner.php" );
117
- ?>
118
-
 
 
 
 
 
119
  </tr>
120
  </table>
 
 
121
  <br />
122
  <table width="100%" cellspacing='3' cellpadding="4" >
123
  <tr><td valign='top' width="160" >
@@ -161,6 +175,7 @@ document.write(d);
161
  //-->
162
  </script></div> </td></tr></table>
163
 
 
164
  <!--XCloner Ads -->
165
  <br />
166
  <table width='100%' cellpadding='5' height='100%' class='menu_table'><tr><td>
@@ -185,6 +200,8 @@ document.write(d);
185
  </center>
186
  </td></td></table>
187
  <!-- END Ads -->
 
 
188
 
189
  </td><td valign='top' align='left' style="padding-left: 20px;">
190
 
@@ -192,7 +209,7 @@ document.write(d);
192
  <?php
193
  if($_REQUEST['mosmsg']!="")
194
 
195
- echo "<center><h2>".$_REQUEST['mosmsg']."</h2></center>";
196
 
197
  }
198
 
@@ -202,9 +219,14 @@ function footer(){
202
  </td></tr></table>
203
  <hr><br /><br />
204
  <center>
205
- <p>Powered by <a href='http://www.xcloner.com' target='_blank'>XCloner</a>. All rights reserved!</p></center>
206
 
207
  </td></tr></table>
 
 
 
 
 
208
 
209
  <?php
210
 
@@ -218,8 +240,9 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
218
  $backupFile = $f['basename'];
219
 
220
  if (file_exists($filename)) {
221
- echo "Backup <strong>$filename</strong> created, we may continue!<br />";
222
- //echo "Database backup: ".$databaseResult ."<br />";
 
223
  $urlReturn = "index2.php?option=com_cloner&lines=" . $perm_lines . "&task=refresh&backup=$backupFile&excl_manual=$excl_manual";
224
 
225
  if(!$_CONFIG['refresh_mode']){
@@ -230,6 +253,8 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
230
 
231
  }else{
232
 
 
 
233
  ?>
234
  <!--Start ProgressBar-->
235
  <script type="text/javascript">
@@ -238,6 +263,13 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
238
 
239
  var globalUrl;
240
  var step = "r1";
 
 
 
 
 
 
 
241
 
242
  $("#progressbar").progressbar({ value: 0 });
243
 
@@ -246,12 +278,22 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
246
  //reset state here;
247
  $("#error").show();
248
  $("#errorText").append(status+" -- "+error);
 
249
  }});
250
 
251
- function xclonerRecurseJSON(url){
252
 
253
- $("#result").hide();
 
 
 
254
 
 
 
 
 
 
 
255
  globalUrl = url;
256
  step = "r1";
257
 
@@ -262,6 +304,56 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
262
  $("#errorText").text(url);
263
  }
264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
  if(!parseInt(json.finished)){
266
 
267
  $("#recurseStatus").text(json.tfiles);
@@ -272,8 +364,18 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
272
  }
273
  else{
274
  var size = parseFloat(json.size)/(1024*1024);
275
- $("#recurseStatus").text(" done! (Estimated size:"+size.toFixed(2)+"MB)");
276
  $("#result").show();
 
 
 
 
 
 
 
 
 
 
277
  //xclonerGetJSON("<?php echo $urlReturn;?>");
278
  returnUrl = "index2.php?option=com_cloner&lines="+json.tfiles+"&task=refresh&backup=<?php echo $backupFile; ?>&excl_manual=";
279
  xclonerGetJSON(returnUrl);
@@ -285,9 +387,9 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
285
  }
286
 
287
  function xclonerGetJSON(url){
288
-
289
  globalUrl = url;
290
- step = "r2";
291
 
292
  $.getJSON(url, function(json) {
293
 
@@ -298,62 +400,145 @@ function goRefreshHtml($filename, $perm_lines, $excl_manual){
298
 
299
  var percent = parseInt(json.percent);
300
  $("#progressbar").progressbar({ value: percent });
301
- $("#backupSize").text(json.backupSize);
302
  $("#nFiles").text(json.startf);
303
  $("#percent").text(json.percent);
 
304
  if(!json.finished){
 
 
 
 
 
 
 
 
 
305
  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;
306
  xclonerGetJSON(url);
307
  }else{
308
 
 
 
 
 
 
309
  $("#complete").show();
310
  $("#nFiles").text(json.lines);
311
-
 
 
312
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
 
314
  });
315
 
316
  }
317
 
 
 
318
  $("#retry").click(function(){
319
  $("#error").hide();
320
  $("#errorText").empty();
321
  if(step == "r1"){
 
 
 
 
322
  xclonerRecurseJSON(globalUrl);
323
  }
324
- else if(step == "r2"){
325
  xclonerGetJSON(globalUrl);
326
  }
327
  });
328
 
329
- var recurseUrl="index2.php?task=recurse_files&mode=start&nohtml=1";
330
- xclonerRecurseJSON(recurseUrl);
331
- //xclonerGetJSON("<?php echo $urlReturn;?>");
 
 
 
 
 
 
 
332
 
 
333
 
334
  });
335
  </script>
336
 
337
- <div id="recurseFiles">
338
- <br /><strong>Scanning files system...</strong> <span id="recurseStatus"></span>
339
- </div>
340
-
341
- <div id="result">
342
- <br /> <strong>Processing Files:</strong> <span id="percent">0</span>% (<span id="nFiles"></span> files)
343
- <br /><br /> <strong>Backup Size: </strong><span id="backupSize"></span>
344
- <br /><br /> <div id="progressbar"></div>
345
- </div>
346
 
347
- <div id="complete">
348
- <br /><h2>Backup completed!</h2>
 
349
 
350
- <form action="index2.php" name="adminForm" method="post">
351
- <input type=hidden name=files[1] value='<?php echo $backupFile?>'>
352
- <input type=hidden name=cid[1] value='<?php echo $backupFile?>'>
353
- <input type="hidden" name="option" value="<?php echo $option; ?>"/>
354
- <input type="hidden" name="task" value=""/>
355
- </form>
356
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
357
  </div>
358
 
359
  <div id="error" style="display:none;">
@@ -402,7 +587,7 @@ function path_check($path){
402
  }
403
 
404
  function _FDefault(){
405
- global $_CONFIG;
406
  ?>
407
 
408
  <form action="index2.php" method="post" name="adminForm">
@@ -477,23 +662,29 @@ $error = 0;
477
  <div class="status">
478
  <span class="mtext">Backup Start Path Check: </span>
479
  <?php
480
-
481
- $stat = HTML_cloner::path_check($_CONFIG[backup_start_path]);
482
 
483
  if( $stat['code'] > 0 and $stat['code'] < 3){
484
  echo "<span class='error'>".$stat['message']; $error = 1;
485
  }
486
  else{
487
  echo "<span class='success'>OK";
488
- }
 
 
 
 
 
489
  echo " ($_CONFIG[backup_start_path])";
490
  ?>
491
  </span></div>
 
492
  <div class="status">
493
  <span class="mtext">Backup Store Path Check: </span>
494
  <?php
495
 
496
- $stat = HTML_cloner::path_check($_CONFIG[backup_store_path]);
497
 
498
  if( $stat['code'] > 0){
499
  echo "<span class='error'>".$stat['message']; $error = 1;
@@ -503,12 +694,14 @@ $error = 0;
503
  }
504
  echo " ($_CONFIG[backup_store_path])";
505
  ?>
506
- </span></div>
 
 
507
  <div class="status">
508
  <span class="mtext">Temporary Path Check: </span>
509
  <?php
510
 
511
- $stat = HTML_cloner::path_check($_CONFIG[temp_dir]);
512
 
513
  if( $stat['code'] > 0){
514
  echo "<span class='error'>".$stat['message']; $error = 1;
@@ -520,6 +713,20 @@ $error = 0;
520
  ?>
521
  </span></div>
522
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
523
  <div class="status">
524
  <span class="mtext">Backup Ready: </span>
525
  <?php
@@ -544,30 +751,61 @@ $error = 0;
544
  <?php
545
  }
546
 
547
- /*The basic authentification form*/
548
  function Login(){
549
 
550
  ?>
551
  <center><br />
552
- <form action="index2.php" method="post" name="adminForm">
553
- <table border='1' ><tr><td align='center'>
554
- <table align='center' cellpadding='10' cellspacing='20'>
555
- <tr ><td colspan='2' align='center'><b>Authentification Area:</b></td></tr>
556
- <tr><td>Username:</td><td><input type='text' size='30' name='username'></td></tr>
557
- <tr><td>Password:</td><td><input type='password' size='30' name='password'></td></tr>
558
- <tr><td></td><td><input type="submit" value='Login' name="login"> <input type="reset" value='Cancel'></td></tr>
559
-
560
- <tr><td colspan='2'><?php echo LM_LOGIN_TEXT;?></td></tr>
561
-
562
- </table>
563
- </td></tr>
564
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
565
 
566
 
 
 
 
 
 
567
  </table>
568
 
569
  <input type="hidden" name="option" value="com_cloner" />
570
- <input type="hidden" name="task" value="dologin" />
571
  <input type="hidden" name="boxchecked" value="0" />
572
  <input type="hidden" name="hidemainmenu" value="0" />
573
 
@@ -580,36 +818,45 @@ function Login(){
580
  function Cron(){
581
  global $_CONFIG;
582
  ?>
583
- <table class='adminform'>
584
- <tr><th>
585
- <?php echo LM_CRON_TOP?>
586
- </th></tr>
587
- <tr><td>
588
- <pre>
589
- <?php echo LM_CRON_SUB?>
590
- <br /><b>For Joomla:</b>
591
- <span style='background: #eeeeee'>
592
- /usr/bin/php <?php echo dirname(__FILE__);?>/cloner.cron.php
593
- <br />
594
- or
595
- <br />
596
- links http://link_to_xcloner_dir/cloner.cron.php
597
- <br />
598
- or
599
- <br />
600
- lynx -source http://link_to_xcloner_dir/cloner.cron.php
601
- </span>
602
 
603
- For <b>Running Multiple Crons</b>, you need to first create a custom configuration file in the XCloner Configuration -> Cron tab
604
- and then replace "cloner.cron.php" with "cloner.cron.php?config=myconfig.php", only use 'links' or 'lynx' options to run the cronjob
 
 
 
605
 
606
- If you would like to use the <b>php SSH command</b> for running Multiple Crons, you will need to replace
607
- the "cloner.cron.php" with <b>"cloner.cron.php myconfig.php"</b> in the command line.
 
 
608
 
609
- <?php echo LM_CRON_HELP?>
610
- </pre>
611
- </td></tr>
612
- </table>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
613
 
614
  <?php
615
  }
@@ -743,29 +990,37 @@ function Translator($option, $lang_arr){
743
  global $_CONFIG;
744
 
745
  ?>
 
 
 
 
 
 
 
746
 
747
- <form action="index2.php" method="post" name="adminForm">
 
748
  <table class="adminlist">
749
  <tr>
750
- <th width="5" align="left">#</th>
751
- <th width="5" align="left">
752
- <input type="checkbox" name="toggle" value="" onClick="checkAll(<?php echo count( $lang_arr ); ?>);" />
753
  </th>
754
  <th align="left">
755
  <?php echo LM_LANG_NAME ?>
756
  </th>
757
  </tr>
758
- <?php
759
 
 
760
  for($i=0; $i<sizeof($lang_arr); $i++){
761
 
762
  ?>
763
 
764
  <tr>
765
- <td width="5" align="left"><?php echo ($i+1);?></td>
766
- <td width="5" align="left">
767
- <input type="checkbox" id="cb<?php echo $i ?>" name="cid[<?php echo $i?>]" value="<?php echo $i ?>" onclick="isChecked(this.checked);" />
768
- <input type="hidden" name="files[<?php echo $i?>]" value="<?php echo $lang_arr[$i] ?>" onclick="isChecked(this.checked);" />
 
769
  </td>
770
  <td align="left" >
771
  <a href="index2.php?option=<?php echo $option;?>&task=edit_lang&langx=<?php echo $lang_arr[$i];?>"><?php echo ucfirst($lang_arr[$i])?>
@@ -775,7 +1030,7 @@ function Translator($option, $lang_arr){
775
 
776
  }
777
  ?>
778
-
779
  <input type="hidden" name="option" value="com_cloner" />
780
  <input type="hidden" name="task" value="lang" />
781
  <input type="hidden" name="boxchecked" value="0" />
@@ -791,23 +1046,65 @@ function showBackups( &$files, &$sizes, $path, $option ) {
791
  global $baDownloadPath, $_CONFIG;
792
 
793
  ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
794
  <form action="index2.php" method="post" name="adminForm">
795
  <table class="adminlist">
796
  <tr>
797
- <th width="5">#</th>
798
- <th width="5">
799
- <input type="checkbox" name="toggle" value="" onClick="checkAll(<?php echo count( $files ); ?>);" />
800
- </th>
801
- <th width="33%" class="title">
802
- <?php echo LM_COL_FILENAME ?>
803
  </th>
804
- <th align="left" width="10%">
805
  <?php echo LM_COL_DOWNLOAD ?>
806
  </th>
 
 
 
807
  <th align="left" width="10%">
808
  <?php echo LM_COL_SIZE ?>
809
  </th>
810
- <th align="left" width="43%">
811
  <?php echo LM_COL_DATE ?>
812
  </th>
813
  </tr>
@@ -815,38 +1112,28 @@ function showBackups( &$files, &$sizes, $path, $option ) {
815
  $k = 0;
816
  for ($i=0; $i <= (count( $files )-1); $i++) {
817
  $date = date ("D jS M Y H:i:s (\G\M\T O)", filemtime($path.'/'.$files[$i]));
 
818
  ?>
819
  <tr class="<?php echo "row$k"; ?>">
820
- <td>
821
- <?php echo $i+1; ?>
822
- </td>
823
  <td align="center">
824
- <input type="checkbox" id="cb<?php echo $i ?>" name="cid[<?php echo $i?>]" value="<?php echo $i ?>" onclick="isChecked(this.checked);" />
825
- <input type="hidden" name="files[<?php echo $i?>]" value="<?php echo $files[$i] ?>" onclick="isChecked(this.checked);" />
826
- </td>
827
- <td >
828
- <a target='_blank' href="<?php echo "index2.php?option=com_cloner&task=download&file=".'/'.urlencode($files[$i]); ?>"><?php echo $files[$i]; ?></a><input type="hidden" id="f<?php echo $i ?>" name="f<?php echo $i ?>" value="<?php echo $files[$i]; ?>" >
829
  </td>
830
  <td align="left">
831
- <a target='_blank' href="<?php echo "index2.php?option=com_cloner&task=download&file=".'/'.urlencode($files[$i]); ?>"><img src="images/filesave.png" border="0" alt="<?php echo LM_DOWNLOAD_TITLE ?>" title="<?php echo LM_DOWNLOAD_TITLE ?>"></a></td >
832
- <!--<td align="left">
833
- <?php
834
-
835
- $userfile = $_CONFIG['baDownloadPath']."/".$files[$i];
836
- $localfile = $_CONFIG['clonerPath']."/".$files[$i];
837
- if(@file_exists($userfile))
838
- echo "<a href=\"index2.php?option=com_cloner&task=action&action=delete&file=$files[$i]\">
839
- <img border='0' src='images/tick.png'></a>";
840
- else
841
- echo "<a href=\"index2.php?option=com_cloner&task=action&action=copy&file=$files[$i]\">
842
- <img border='0' src='images/publish_x.png'></a>";
843
- ?>
844
- </td>-->
845
  <td align="left">
846
- <?php echo $sizes[$i]; ?>
847
  </td >
848
  <td align="left">
849
- <?php echo $date; ?>
850
  </td>
851
  </tr>
852
  <?php
@@ -854,7 +1141,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
854
  }
855
  ?>
856
  </table>
857
-
858
  <input type="hidden" name="option" value="com_cloner" />
859
  <input type="hidden" name="task" value="" />
860
  <input type="hidden" name="boxchecked" value="0" />
@@ -868,914 +1155,1138 @@ function showBackups( &$files, &$sizes, $path, $option ) {
868
  global $config_file,$_CONFIG, $lang_array, $database, $mosConfig_db;
869
  ?>
870
  <form name='adminForm' action='index2.php' method='POST'>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
871
  <table class='adminform'>
872
  <tr><th colspan='2'>
873
  <?php echo LM_CONFIG_EDIT?> <?php echo $config_file?>
874
  </th></tr>
875
  </table>
876
  <?php
877
- $tabs = new mosTabs(1);
878
- $tabs->startTab(LM_TAB_GENERAL,"config-general-tab");
879
  ?>
880
- <table class='adminform'>
881
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
882
 
883
- <tr>
884
- <th colspan='2'>
885
- <?php echo LM_CONFIG_BSETTINGS?>
886
- </th>
887
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
888
 
889
- <tr>
890
- <td>
891
- <?php echo LM_CONFIG_UBPATH?>
892
- </td>
893
- <td>
894
- <input type=text size=50 name='backup_path' value='<?php echo $_CONFIG[backup_path]?>'>
895
- <br /><?php echo LM_CONFIG_UBPATH_SUB?>
896
- </td>
897
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
898
 
899
- <tr>
900
- <td width='250'>
901
- <?php echo LM_CONFIG_BPATH?>
902
- </td>
903
- <td>
904
- <input type=text size=50 name='clonerPath' value='<?php echo $_CONFIG[clonerPath]?>'>
905
- <br /><?php echo LM_CONFIG_BPATH_SUB?>
906
- </td>
907
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
908
 
 
 
 
 
 
 
 
 
909
 
910
- <tr>
911
- <th colspan='2'>
912
- <?php echo LM_CONFIG_BSETTINGS_OPTIONS?>
913
- </th>
914
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
915
 
916
- <tr>
917
- <td>
918
- <?php echo LM_CONFIG_MANUAL_BACKUP;?>
919
- </td>
920
- <td>
921
- <?php echo LM_YES?> <input type=radio size=50 value=1 name='backup_refresh' <?php if($_CONFIG[backup_refresh]==1) echo 'checked';?>>
922
- <?php echo LM_NO?> <input type=radio size=50 value=0 name='backup_refresh' <?php if($_CONFIG[backup_refresh]==0) echo 'checked';?>>
923
- <br><small><?php echo LM_CONFIG_MANUAL_BACKUP_SUB?></small>
924
- </td>
925
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
926
 
927
- <tr>
928
- <td>
929
- <?php echo LM_CRON_COMPRESS?>
930
- </td>
931
- <td>
932
- <?php echo LM_YES?> <input type=radio size=50 value=1 name='backup_compress' <?php if($_CONFIG[backup_compress]==1) echo 'checked';?>>
933
- <?php echo LM_NO?> <input type=radio size=50 value=0 name='backup_compress' <?php if($_CONFIG[backup_compress]==0) echo 'checked';?>>
934
- <br /> <small>set it to Yes in order to compress the files into smaller backups</small>
935
- </td>
936
- </tr>
937
 
938
- <tr>
939
- <td>
940
- <?php echo LM_CRON_DB_BACKUP?>
941
- </td>
942
- <td>
943
- Yes <input type=radio size=50 value=1 name='enable_db_backup' <?php if($_CONFIG[enable_db_backup]==1) echo 'checked';?>>
944
- No <input type=radio size=50 value=0 name='enable_db_backup' <?php if($_CONFIG[enable_db_backup]==0) echo 'checked';?>>
945
- <br />
946
- <?php echo LM_CRON_DB_BACKUP_SUB?>
947
- </td>
948
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
949
 
950
- <tr>
951
- <td>
952
- <?php echo LM_CONFIG_SYSTEM_MBACKUP?>
953
- </td>
954
- <td>
955
- Yes <input type=radio size=50 value=1 name='add_backups_dir' <?php if($_CONFIG[add_backups_dir]==1) echo 'checked';?>>
956
- No <input type=radio size=50 value=0 name='add_backups_dir' <?php if($_CONFIG[add_backups_dir]==0) echo 'checked';?>>
957
- <br />
958
- <?php echo LM_CONFIG_SYSTEM_MBACKUP_SUB?>
959
- </td>
960
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
961
 
962
- <tr>
963
- <th colspan='2'>
964
- <?php echo LM_CONFIG_BSETTINGS_SERVER?>
965
- </th>
966
- </tr>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
967
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
968
 
969
- <tr >
970
- <td>
971
- <?php echo LM_CONFIG_MEM?>
972
- </td>
973
- <td align='left'>
974
- <table width='85%' cellpadding='0' cellspacing='2' border='1'>
975
- <tr bgcolor='#efefef'><td valign='middle'>
976
- <?php echo LM_ACTIVE;?> <input type=checkbox value=1 name='mem' <?php if($_CONFIG[mem]==1) echo 'checked';?>>
977
- </td><td align='left'>
978
 
979
- <table width='100%' cellpadding='0' cellspacing='0'>
980
- <tr><td>
981
- <?php echo LM_TAR_PATH;?> <br /><input size='50' type=text name=tarpath value='<?php echo $_CONFIG[tarpath]?>'><br />
982
- <?php echo LM_TAR_PATH_SUB;?>
983
- </td></tr>
984
 
985
- </table>
 
 
 
 
 
 
 
986
 
987
- </td></tr>
 
988
 
989
- <tr bgcolor='#dedede'><td>
990
- <?php echo LM_ACTIVE?> <input type=checkbox value=1 name='sql_mem' <?php if($_CONFIG[sql_mem]==1) echo 'checked';?>>
991
- </td><td align='left'>
992
- <?php echo LM_MYSQLDUMP_PATH;?> <br /><input type=text size='50' name='sqldump' value='<?php echo $_CONFIG[sqldump]?>'>
993
 
994
- </td></tr>
995
- </table>
 
 
996
 
997
- <?php echo LM_CONFIG_MEM_SUB?>
998
 
999
- </td>
1000
- </tr>
1001
 
1002
- <tr>
1003
- <th colspan='2'>
1004
- <?php echo "License Management"?>
1005
- </th>
1006
- </tr>
1007
- <tr>
1008
- <td>
1009
- <?php echo "License Code - optional*
1010
- <br />*only for support purposes"?>
1011
- </td>
1012
- <td>
1013
- <textarea cols=40 rows='7' name='license_code' ><?php echo $_CONFIG[license_code]?></textarea>
1014
- <br />Copy/Paste the license code from <a target='_blank' href='http://www.xcloner.com/'>XCloner.com Members area</a>
1015
- </td>
1016
- </tr>
1017
-
1018
-
1019
- </table>
1020
- <?php
1021
- $tabs->endTab();
1022
- $tabs->startTab(LM_TAB_MYSQL,"config-mysql-tab");
1023
- ?>
1024
- <table class='adminform'>
1025
-
1026
-
1027
- <tr>
1028
- <th colspan='2'>
1029
- <?php echo LM_CONFIG_MYSQL?>
1030
- </th>
1031
- </tr>
1032
-
1033
- <tr>
1034
- <td>
1035
- <?php echo LM_CONFIG_MYSQLH?>
1036
- </td>
1037
- <td>
1038
- <input type=text size=50 name='mysql_host' value='<?php echo $_CONFIG[mysql_host]?>'>
1039
- <br /><?php echo LM_CONFIG_MYSQLH_SUB?>
1040
- </td>
1041
- </tr>
1042
-
1043
- <tr>
1044
- <td>
1045
- <?php echo LM_CONFIG_MYSQLU?>
1046
- </td>
1047
- <td>
1048
- <input type=text size=50 name='mysql_user' value='<?php echo $_CONFIG[mysql_user]?>'>
1049
- <br /><?php echo LM_CONFIG_MYSQLU_SUB?>
1050
- </td>
1051
- </tr>
1052
-
1053
- <tr>
1054
- <td>
1055
- <?php echo LM_CONFIG_MYSQLP?>
1056
- </td>
1057
- <td>
1058
- <input type=text size=50 name='mysql_pass' value='<?php echo $_CONFIG[mysql_pass]?>'>
1059
- <br /><?php echo LM_CONFIG_MYSQLP_SUB?>
1060
- </td>
1061
- </tr>
1062
-
1063
- <tr>
1064
- <td>
1065
- <?php echo LM_CONFIG_MYSQLD?>
1066
- </td>
1067
- <td>
1068
- <input type=text size=50 name='mysql_database' value='<?php echo $_CONFIG[mysql_database]?>'>
1069
- <br /><?php echo LM_CONFIG_MYSQLD_SUB?>
1070
- </td>
1071
- </tr>
1072
-
1073
- <tr>
1074
- <td width='200'>
1075
- <?php echo LM_CONFIG_SYSTEM_MDATABASES?>
1076
- </td>
1077
- <td>
1078
- <?php echo LM_YES?> <input type=radio name='system_mdatabases' value='0' <?php if(abs($_CONFIG[system_mdatabases])==0) echo "checked";?>>
1079
- <?php echo LM_NO?> <input type=radio name='system_mdatabases' value='1' <?php if(abs($_CONFIG[system_mdatabases])==1) echo "checked";?>>
1080
- <br>
1081
-
1082
- <br /><?php echo LM_CONFIG_SYSTEM_MDATABASES_SUB?>
1083
- </td>
1084
- </tr>
1085
-
1086
- </table>
1087
- <?php
1088
- $tabs->endTab();
1089
- $tabs->startTab(LM_TAB_AUTH,"config-mysql-tab");
1090
- ?>
1091
- <table class='adminform'>
1092
-
1093
-
1094
- <tr>
1095
- <th colspan='2'>
1096
- <?php echo LM_CONFIG_AUTH?>
1097
- </th>
1098
- </tr>
1099
-
1100
- <tr>
1101
- <td>
1102
- <?php echo LM_CONFIG_AUTH_USER?>
1103
- </td>
1104
- <td>
1105
- <input type=text size=30 name='jcuser' value='<?php echo $_CONFIG[jcuser]?>'>
1106
- <br /><?php echo LM_CONFIG_AUTH_USER_SUB?>
1107
- </td>
1108
- </tr>
1109
-
1110
- <tr>
1111
- <td>
1112
- <?php echo LM_CONFIG_AUTH_PASS?>
1113
- </td>
1114
- <td>
1115
- <input type=text size=30 name='jcpass' value=''> <?php if($_CONFIG['jcpass'] == md5('admin')) echo "<font color=red>please change the default password 'admin'</font>"?>
1116
- <br /><?php echo LM_CONFIG_AUTH_PASS_SUB?>
1117
- </td>
1118
- </tr>
1119
-
1120
-
1121
- </table>
1122
- <?php
1123
- $tabs->endTab();
1124
- $tabs->startTab(LM_TAB_SYSTEM,"config-system-tab");
1125
- ?>
1126
- <table class='adminform'>
1127
- <tr>
1128
- <th colspan='2'>
1129
- <?php echo LM_CONFIG_DISPLAY?>
1130
- </th>
1131
- </tr>
1132
-
1133
- <tr>
1134
- <td width='200'>
1135
- <?php echo LM_CONFIG_SYSTEM_LANG?>
1136
- </td>
1137
- <td>
1138
- <select name='select_lang'>
1139
- <option value=''><?php echo LM_CONFIG_SYSTEM_LANG_DEFAULT;?></option>
1140
- <?php
1141
- foreach($lang_array as $value)
1142
- if($_CONFIG['select_lang'] == $value)
1143
- echo "<option value='$value' selected>$value</option>\n";
1144
- else
1145
- echo "<option value='$value'>$value</option>\n";
1146
- ?>
1147
- </select>
1148
- <br>
1149
- <br /><?php echo LM_CONFIG_SYSTEM_LANG_SUB?>
1150
- </td>
1151
- </tr>
1152
-
1153
-
1154
- <!--<tr>
1155
- <td width='200'>
1156
- <?php echo LM_CONFIG_SYSTEM_DOWNLOAD?>
1157
- </td>
1158
- <td>
1159
- <?php echo LM_YES?> <input type=radio name='system_dlink' value='1' <?php if(abs($_CONFIG[system_dlink])==1) echo "checked";?>>
1160
- <?php echo LM_NO?> <input type=radio name='system_dlink' value='0' <?php if(abs($_CONFIG[system_dlink])==0) echo "checked";?>>
1161
- <br>
1162
-
1163
- <br /><?php echo LM_CONFIG_SYSTEM_DOWNLOAD_SUB?>
1164
- </td>
1165
- </tr>-->
1166
-
1167
-
1168
- <tr>
1169
- <th colspan='2'>
1170
- <?php echo LM_CONFIG_SYSTEM?>
1171
- </th>
1172
- </tr>
1173
-
1174
- <tr>
1175
- <td width='200'>
1176
- <?php echo LM_CONFIG_SYSTEM_FTP?>
1177
- </td>
1178
- <td>
1179
- Direct <input type=radio name='system_ftptransfer' value='0' <?php if(abs($_CONFIG[system_ftptransfer])==0) echo "checked";?>>
1180
- Passive <input type=radio name='system_ftptransfer' value='1' <?php if(abs($_CONFIG[system_ftptransfer])==1) echo "checked";?>> <br>
1181
-
1182
- <br /><?php echo LM_CONFIG_SYSTEM_FTP_SUB?>
1183
- </td>
1184
- </tr>
1185
- <tr>
1186
- <td>
1187
- <?php echo LM_FTP_TRANSFER_MORE?>
1188
- </td>
1189
- <td>
1190
- Normal <input type=radio size=50 value=0 name='secure_ftp' <?php if($_CONFIG[secure_ftp]==0) echo 'checked';?>>
1191
- Secure <input type=radio size=50 value=1 name='secure_ftp' <?php if($_CONFIG[secure_ftp]==1) echo 'checked';?>>
1192
- </td>
1193
- </tr>
1194
-
1195
- <th colspan='2'>
1196
- <?php echo LM_CONFIG_MANUAL?>
1197
- </th>
1198
- </tr>
1199
-
1200
- <tr>
1201
- <td>
1202
- <?php echo LM_CONFIG_MANUAL_FILES;?>
1203
- </td>
1204
- <td>
1205
- <input type=text size=20 name='backup_refresh_number' value=<?php echo $_CONFIG[backup_refresh_number];?>>
1206
-
1207
- </td>
1208
- </tr>
1209
-
1210
- <tr>
1211
- <td>
1212
- <?php echo LM_CONFIG_MANUAL_REFRESH;?>
1213
- </td>
1214
- <td>
1215
- <input type=text size=20 name='refresh_time' value=<?php echo $_CONFIG[refresh_time];?>> seconds
1216
-
1217
- </td>
1218
- </tr>
1219
-
1220
- <tr>
1221
- <td>
1222
- <?php echo LM_REFRESH_MODE?>
1223
- </td>
1224
- <td>
1225
- Normal <input type=radio size=50 value=0 name='refresh_mode' <?php if($_CONFIG[refresh_mode]==0) echo 'checked';?>>
1226
- AJAX <input type=radio size=50 value=1 name='refresh_mode' <?php if($_CONFIG[refresh_mode]==1) echo 'checked';?>>
1227
- </td>
1228
- </tr>
1229
-
1230
- <tr>
1231
- <td>
1232
- <?php echo LM_DEBUG_MODE?>
1233
- </td>
1234
- <td>
1235
- No <input type=radio size=50 value=0 name='debug' <?php if($_CONFIG[debug]==0) echo 'checked';?>>
1236
- Yes <input type=radio size=50 value=1 name='debug' <?php if($_CONFIG[debug]==1) echo 'checked';?>>
1237
- </td>
1238
- </tr>
1239
-
1240
- </table>
1241
- <?php
1242
- $tabs->endTab();
1243
- $tabs->startTab(LM_TAB_CRON,"config-cron-tab");
1244
- ?>
1245
- <table class='adminform'>
1246
- <tr>
1247
- <th colspan='2'>
1248
- <?php echo LM_CRON_SETTINGS_M?> - all configs are saved in configs/
1249
- </th>
1250
- </tr>
1251
-
1252
- <tr>
1253
- <td>
1254
- <?php echo LM_CRON_MCRON?>
1255
- </td>
1256
- <td>
1257
- <input type=text size=30 value="<?php echo $_CONFIG[cron_save_as]?>" name='cron_save_as' >.php <br />
1258
- <?php echo LM_CRON_MCRON_SUB?>
1259
- </td>
1260
- </tr>
1261
-
1262
- <tr>
1263
- <td>
1264
- <?php echo LM_CRON_MCRON_AVAIL?>
1265
- </td>
1266
- <td>
1267
- <?php
1268
-
1269
- if ($handle = @opendir($_CONFIG['multiple_config_dir'])) {
1270
-
1271
- while (false !== ($file = readdir($handle))) {
1272
- if( ($file!=".") && ($file!="..") &&($file!="") && (strstr($file, '.php'))){
1273
- $fcron = "cloner.cron.php?config=$file";
1274
-
1275
- echo "<b>$fcron</b>";
1276
-
1277
- echo " - <a href='$fcron' target='_blank'>execute cron</a>";
1278
-
1279
- echo " | <a href='index2.php?option=com_cloner&task=cron_delete&fconfig=$file'>delete config</a>";
1280
-
1281
- echo "\n<br />";
1282
- }
1283
- }
1284
-
1285
- closedir($handle);
1286
- }
1287
- ?>
1288
- </td>
1289
- </tr>
1290
-
1291
- <tr>
1292
- <th colspan='2'>
1293
- <?php echo LM_CRON_SETTINGS?>
1294
- </th>
1295
- </tr>
1296
-
1297
- <tr>
1298
- <td>
1299
- <?php echo LM_CRON_SEMAIL?>
1300
- </td>
1301
- <td>
1302
- <input type=text size=30 value="<?php echo $_CONFIG[cron_logemail]?>" name='cron_logemail' > <br />
1303
- <?php echo LM_CRON_SEMAIL_SUB?>
1304
- </td>
1305
- </tr>
1306
-
1307
- <tr>
1308
- <td width='200'>
1309
- <?php echo LM_CRON_MODE?>
1310
- </td>
1311
- <td>
1312
- <input type=radio size=50 value=0 name='cron_send' <?php if($_CONFIG[cron_send]==0) echo 'checked';?>>
1313
- <?php echo LM_CONFIG_CRON_LOCAL?><br />
1314
- <input type=radio size=50 value=1 name='cron_send' <?php if($_CONFIG[cron_send]==1) echo 'checked';?>>
1315
- <?php echo LM_CONFIG_CRON_REMOTE?><br />
1316
- <input type=radio size=50 value=2 name='cron_send' <?php if($_CONFIG[cron_send]==2) echo 'checked';?>>
1317
- <?php echo LM_CONFIG_CRON_EMAIL?> <br />
1318
- <?php echo LM_CRON_MODE_INFO?>
1319
- </td>
1320
- </tr>
1321
-
1322
-
1323
- <tr>
1324
- <td>
1325
- <?php echo LM_CRON_TYPE?>
1326
- </td>
1327
- <td>
1328
- <input type=radio size=50 value=0 name='cron_btype' <?php if($_CONFIG[cron_btype]==0) echo 'checked';?>>
1329
- <?php echo LM_CONFIG_CRON_FULL?> <br />
1330
- <input type=radio size=50 value=1 name='cron_btype' <?php if($_CONFIG[cron_btype]==1) echo 'checked';?>>
1331
- <?php echo LM_CONFIG_CRON_FILES?><br />
1332
- <input type=radio size=50 value=2 name='cron_btype' <?php if($_CONFIG[cron_btype]==2) echo 'checked';?>>
1333
- <?php echo LM_CONFIG_CRON_DATABASE?> <br />
1334
- <?php echo LM_CRON_TYPE_INFO?>
1335
- </td>
1336
- </tr>
1337
-
1338
- <tr>
1339
- <td>
1340
- <?php echo LM_CRON_BNAME?>
1341
- </td>
1342
- <td>
1343
- <input type=text size=50 value="<?php echo $_CONFIG[cron_bname]?>" name='cron_bname' > <br />
1344
- <?php echo LM_CRON_BNAME_SUB?>
1345
- </td>
1346
- </tr>
1347
-
1348
-
1349
- <tr>
1350
- <td>
1351
- <?php echo LM_CRON_IP?>
1352
- </td>
1353
- <td>
1354
- <textarea type=text size=50 name='cron_ip' cols='30' rows='5'><?php echo $_CONFIG[cron_ip]?></textarea> <br />
1355
- <?php echo LM_CRON_IP_SUB?>
1356
- </td>
1357
- </tr>
1358
-
1359
- </table>
1360
- <table class='adminform'>
1361
- <tr>
1362
- <th colspan='2'>
1363
- <?php echo LM_CRON_FTP_DETAILS?>
1364
- </th>
1365
- </tr>
1366
- </tr>
1367
- <tr>
1368
- <td width='200'>
1369
- <?php echo LM_CRON_FTP_SERVER?>
1370
- </td>
1371
- <td>
1372
- <input type=text size=50 name='cron_ftp_server' value='<?php echo $_CONFIG[cron_ftp_server]?>'>
1373
- </td>
1374
- </tr>
1375
- <tr>
1376
- <td>
1377
- <?php echo LM_CRON_FTP_USER?>
1378
- </td>
1379
- <td>
1380
- <input type=text size=50 name='cron_ftp_user' value='<?php echo $_CONFIG[cron_ftp_user]?>'>
1381
- </td>
1382
- </tr>
1383
- <tr>
1384
- <td>
1385
- <?php echo LM_CRON_FTP_PASS?>
1386
- </td>
1387
- <td>
1388
- <input type=text size=50 name='cron_ftp_pass' value='<?php echo $_CONFIG[cron_ftp_pass]?>'>
1389
- </td>
1390
- </tr>
1391
- <tr>
1392
- <td>
1393
- <?php echo LM_CRON_FTP_PATH?>
1394
- </td>
1395
- <td>
1396
- <input type=text size=50 name='cron_ftp_path' value='<?php echo $_CONFIG[cron_ftp_path]?>'>
1397
- </td>
1398
- </tr>
1399
- <tr>
1400
- <td>
1401
- <?php echo LM_CRON_FTP_DELB?>
1402
- </td>
1403
- <td>
1404
- <input type=checkbox name='cron_ftp_delb' <?php if($_CONFIG[cron_ftp_delb]==1) echo "checked";?> value='1'>
1405
- </td>
1406
- </tr>
1407
- </table>
1408
-
1409
- <table class='adminform'>
1410
-
1411
- <tr><th colspan=2>
1412
- <?php echo LM_AMAZON_S3?>
1413
- </th></tr>
1414
- <tr>
1415
- <td width='200'>
1416
- <?php echo LM_AMAZON_S3_ACTIVATE?>
1417
- </td>
1418
- <td>
1419
- <input type=checkbox name='cron_amazon_active' <?php if($_CONFIG[cron_amazon_active]==1) echo "checked";?> value='1'>
1420
- </td>
1421
- </tr>
1422
-
1423
- <tr>
1424
- <td width='200'>
1425
- <?php echo LM_AMAZON_S3_AWSACCESSKEY;?>
1426
- </td>
1427
- <td>
1428
- <input type=text size=50 name='cron_amazon_awsAccessKey' value="<?php echo $_CONFIG['cron_amazon_awsAccessKey'];?>">
1429
- </td>
1430
- </tr>
1431
-
1432
- <tr>
1433
- <td width='200'>
1434
- <?php echo LM_AMAZON_S3_AWSSECRETKEY;?>
1435
- </td>
1436
- <td>
1437
- <input type=text size=50 name='cron_amazon_awsSecretKey' value="<?php echo $_CONFIG['cron_amazon_awsSecretKey'];?>">
1438
- </td>
1439
- </tr>
1440
-
1441
- <tr>
1442
- <td width='200'>
1443
- <?php echo LM_AMAZON_S3_BUCKET;?>
1444
- </td>
1445
- <td>
1446
- <input type=text size=50 name='cron_amazon_bucket' value="<?php echo $_CONFIG['cron_amazon_bucket'];?>">
1447
- </td>
1448
- </tr>
1449
-
1450
- <tr>
1451
- <td width='200'>
1452
- <?php echo LM_AMAZON_S3_DIRNAME;?>
1453
- </td>
1454
- <td>
1455
- <input type=text size=50 name='cron_amazon_dirname' value="<?php echo $_CONFIG['cron_amazon_dirname'];?>">
1456
- </td>
1457
- </tr>
1458
-
1459
- <td>
1460
-
1461
- </td>
1462
- </tr>
1463
-
1464
- </table>
1465
-
1466
-
1467
- <table class='adminform'>
1468
- <tr>
1469
- <th colspan='2'>
1470
- <?php echo LM_CRON_EMAIL_DETAILS?>
1471
- </th>
1472
- </tr>
1473
- </tr>
1474
- <tr>
1475
- <td width='200'>
1476
- <?php echo LM_CRON_EMAIL_ACCOUNT?>
1477
- </td>
1478
- <td>
1479
- <input type=text size=50 name='cron_email_address' value='<?php echo $_CONFIG[cron_email_address]?>'>
1480
- </td>
1481
- </tr>
1482
-
1483
-
1484
- </table>
1485
-
1486
- <table class='adminform'>
1487
- <tr>
1488
- <th colspan='2'>
1489
- <?php echo LM_CRON_MYSQL_DETAILS?>
1490
- </th>
1491
- </tr>
1492
- </tr>
1493
- <tr bgcolor='#ffffff'>
1494
- <td width='200'>
1495
- <?php echo LM_CRON_MYSQL_DROP?>
1496
- </td>
1497
- <td>
1498
- <input type=checkbox name='cron_sql_drop' value='1' <?php if($_CONFIG[cron_sql_drop]) echo "checked";?> >
1499
- </td>
1500
- </tr>
1501
-
1502
- <?php
1503
- if((abs($_CONFIG[system_mdatabases])==0) && ($_CONFIG[enable_db_backup]==1)){
1504
- ?>
1505
- <tr><td valign='top'>
1506
- <?php echo LM_DATABASE_INCLUDE_DATABASES?>
1507
- </td><td>
1508
- <select name='databases_incl[]' MULTIPLE SIZE=5>
1509
- <?php
1510
-
1511
- $curent_dbs = explode(",", $_CONFIG['databases_incl_list']);
1512
-
1513
- $query = @mysql_query("SHOW databases");
1514
- while($row = @mysql_fetch_array($query)){
1515
-
1516
- $table = $row[0];
1517
-
1518
- if($table != $_CONFIG['mysql_database'])
1519
-
1520
- if(in_array($table, $curent_dbs)){
1521
-
1522
- echo "<option value='".$table."' selected>$table</option>";
1523
-
1524
- }else{
1525
-
1526
- echo "<option value='".$table."'>$table</option>";
1527
-
1528
- }
1529
- }
1530
- ?>
1531
- </select><br />
1532
- <?php echo LM_DATABASE_INCLUDE_DATABASES_SUB?>
1533
- </td></tr>
1534
- <?php
1535
- }
1536
- ?>
1537
-
1538
- <tr><th colspan=2>
1539
- <?php echo LM_CRON_DELETE_FILES?>
1540
- </th></tr>
1541
- <tr>
1542
- <td width='200'>
1543
- <?php echo LM_CRON_DELETE_FILES_SUB_ACTIVE?>
1544
- </td>
1545
- <td>
1546
- <input type=checkbox name='cron_file_delete_act' <?php if ($_CONFIG['cron_file_delete_act'] == 1) echo 'checked';?> value='1'>
1547
- </td>
1548
- </tr>
1549
- <tr>
1550
- <td width='200'>
1551
- <?php echo LM_CRON_DELETE_FILES_SUB?>
1552
- </td>
1553
- <td>
1554
- <input size=5 name='cron_file_delete' value='<?php echo $_CONFIG[cron_file_delete]?>'> days:
1555
- </td>
1556
- </tr>
1557
- </table>
1558
-
1559
- <table class='adminform'>
1560
- <tr>
1561
- <th colspan='2'>
1562
- <?php echo LM_CRON_EXCLUDE?>
1563
- </th>
1564
- </tr>
1565
- </tr>
1566
- <tr>
1567
- <td width='200'>
1568
- <?php echo LM_CRON_EXCLUDE_DIR?>
1569
- </td>
1570
- <td>
1571
- <textarea cols=50 rows=5 name='cron_exclude'><?php echo $_CONFIG[cron_exclude]?></textarea>
1572
- </td>
1573
- </tr>
1574
-
1575
- </table>
1576
- <?php
1577
- $tabs->endTab();
1578
- $tabs->startTab(LM_TAB_INFO,"config-info-tab");
1579
- ?>
1580
- <table class='adminform'>
1581
- <tr>
1582
- <th colspan='2'>
1583
- <?php echo LM_CONFIG_INFO_PHP?>
1584
- </th>
1585
- </tr>
1586
-
1587
- <tr>
1588
- <td width='200'>
1589
- <?php echo LM_CONFIG_INFO_T_VERSION?>
1590
- </td>
1591
- <td>
1592
- <b><?php
1593
- $version = phpversion();
1594
- $ver = str_replace(".", "", $version);
1595
- $val = ($ver < 520)? $version: "Off";
1596
- echo HTML_cloner::get_color($version, $val);
1597
- ?></b>
1598
- <br />
1599
- <?php echo LM_CONFIG_INFO_VERSION?>
1600
- </td>
1601
- </tr>
1602
-
1603
- <tr>
1604
- <td width='200'>
1605
- <?php echo LM_CONFIG_INFO_T_SAFEMODE?>
1606
- </td>
1607
- <td>
1608
- <b><?php $val = (ini_get('safe_mode') != "")? ini_get('safe_mode'):"Off";
1609
- echo HTML_cloner::get_color($val, 'On');
1610
- ?></b>
1611
- <br />
1612
- <?php echo LM_CONFIG_INFO_SAFEMODE?>
1613
- </td>
1614
- </tr>
1615
-
1616
- <tr>
1617
- <td width='200'>
1618
- <?php echo LM_CONFIG_INFO_T_MTIME?>
1619
- </td>
1620
- <td>
1621
- <b><?php echo (ini_get('max_execution_time') != "")? ini_get('max_execution_time'):"no value";
1622
-
1623
- ?></b>
1624
- <br />
1625
- <?php echo LM_CONFIG_INFO_TIME?>
1626
- </td>
1627
- </tr>
1628
-
1629
- <tr>
1630
- <td width='200'>
1631
- <?php echo LM_CONFIG_INFO_T_MEML?>
1632
- </td>
1633
- <td>
1634
- <b><?php echo (ini_get('memory_limit') != "")? ini_get('memory_limit'):"no value";?> </b>
1635
- <br />
1636
- <?php echo LM_CONFIG_INFO_MEMORY?>
1637
- </td>
1638
- </tr>
1639
-
1640
- <tr>
1641
- <td width='200'>
1642
- <?php echo LM_CONFIG_INFO_T_BDIR?>
1643
- </td>
1644
- <td>
1645
- <b><?php $val = (ini_get('open_basedir') != "")? ini_get('open_basedir'):"no value";
1646
- echo HTML_cloner::get_color($val, '/');
1647
- ?> </b>
1648
- <br />
1649
- <?php echo LM_CONFIG_INFO_BASEDIR?>
1650
- </td>
1651
- </tr>
1652
-
1653
- <tr>
1654
- <td width='200'>
1655
- <?php echo LM_CONFIG_INFO_T_EXEC?>
1656
- </td>
1657
- <td>
1658
- <b><?php
1659
-
1660
- $out = "";
1661
- if(function_exists("exec")){
1662
-
1663
- $out = @exec("ls -al");
1664
- }
1665
-
1666
- $val = ($out != "")? "ENABLED":"<font color='red'>DISABLED</font>";
1667
- echo HTML_cloner::get_color($val, 'DISABLED');
1668
- ?> </b>
1669
- <br />
1670
- <?php echo LM_CONFIG_INFO_EXEC?>
1671
- </td>
1672
- </tr>
1673
-
1674
- <tr>
1675
- <th colspan='2'>
1676
- <?php echo LM_CONFIG_INFO_PATHS?>
1677
- </td>
1678
- <td>
1679
- </tr>
1680
-
1681
- <tr>
1682
- <td width='200'>
1683
- <?php echo LM_CONFIG_INFO_ROOT_BPATH_TMP?>
1684
- </td>
1685
- <td>
1686
- <b><?php $tmp_dir = realpath($_CONFIG['backup_path']."/administrator/backups");
1687
- echo (@is_writeable( $tmp_dir ))? $tmp_dir . " is <font color=green>writeable</font>":$tmp_dir. " <font color=red>incorrect or unreadable</font>";?></b>
1688
- <br />
1689
- <?php echo LM_CONFIG_INFO_ROOT_PATH_TMP_SUB?>
1690
- </td>
1691
- </tr>
1692
-
1693
- <tr>
1694
- <td width='200'>
1695
- <?php echo LM_CONFIG_INFO_ROOT_BPATH?>
1696
- </td>
1697
- <td>
1698
- <b><?php echo (@is_readable($_CONFIG['backup_path']) )? $_CONFIG['backup_path'] . " is <font color=green>readable</font>":$_CONFIG['backup_path']. " <font color=red>incorrect or unreadable</font>";?></b>
1699
- <br />
1700
- <?php echo LM_CONFIG_INFO_ROOT_PATH_SUB?>
1701
- </td>
1702
- </tr>
1703
-
1704
-
1705
- <tr>
1706
- <td width='200'>
1707
- <?php echo LM_CONFIG_INFO_T_BPATH?>
1708
- </td>
1709
- <td>
1710
- <b><?php echo (@is_writeable($_CONFIG['clonerPath']) )? $_CONFIG['clonerPath'] . " is <font color=green>writeable</font>":$_CONFIG['clonerPath']. " <font color=red>unwriteable</font>";?></b>
1711
- <br />
1712
- <?php echo LM_CONFIG_INFO_BPATH?>
1713
- </td>
1714
- </tr>
1715
-
1716
-
1717
- <tr>
1718
- <td width='200'>
1719
- <?php echo LM_CONFIG_INFO_T_TAR?>
1720
- </td>
1721
- <td>
1722
- <b><?php
1723
- if(function_exists('exec')){
1724
- $info_tar_path = explode(" ", @exec("whereis tar"));
1725
- }
1726
- echo ($info_tar_path['1'] != "")? $info_tar_path['1']:"unable to determine";
1727
- ?> </b>
1728
- <br />
1729
- <?php echo LM_CONFIG_INFO_TAR?>
1730
- </td>
1731
- </tr>
1732
-
1733
-
1734
- <tr>
1735
- <td width='200'>
1736
- <?php echo LM_CONFIG_INFO_T_MSQL?>
1737
- </td>
1738
- <td>
1739
- <b><?php
1740
- if(function_exists('exec')){
1741
- $info_msql_path = explode(" ", @exec("whereis mysqldump"));
1742
- }
1743
- echo ($info_msql_path['1'] != "")? $info_msql_path['1']:"unable to determine";
1744
- ?> </b>
1745
- <br />
1746
- <?php echo LM_CONFIG_INFO_MSQL?>
1747
- </td>
1748
- </tr>
1749
-
1750
-
1751
- </table>
1752
- <?php
1753
- $tabs->endTab();
1754
- $tabs->endPane();
1755
- ?>
1756
- <input type="hidden" name="option" value="com_cloner" />
1757
- <input type="hidden" name="task" value="config" />
1758
- <input type="hidden" name='action' value='save'>
1759
- </form>
1760
-
1761
- <?php
1762
- }
1763
-
1764
- function get_color($val, $comp){
1765
-
1766
- if(!stristr($val, $comp))
1767
- echo "<span style='color:green'>$val</span>";
1768
- else
1769
- echo "<span style='color:red'>$val</span>";
1770
-
1771
- }
1772
-
1773
- function TransferForm($option, $files){
1774
- global $baDownloadPath, $mosConfig_absolute_path, $clonerPath, $task;
1775
-
1776
- ?>
1777
- <form action="index2.php" method="GET" name="adminForm">
1778
- <script language="javascript" type="text/javascript">
1779
 
1780
 
1781
  function submitbutton(pressbutton) {
@@ -1877,23 +2388,48 @@ function showBackups( &$files, &$sizes, $path, $option ) {
1877
  <form action="index2.php" method="post" name="adminForm">
1878
  <?php
1879
  $tabs = new mosTabs(1);
1880
- #$tabs->startPane("BGeneratePane");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1881
  if($_CONFIG['enable_db_backup']){
1882
  $tabs->startTab(LM_TAB_G_DATABASE,"users-databse-options-tab");
1883
  ?>
1884
 
1885
-
1886
  <table class="adminform">
1887
- <tr>
1888
  <th colspan=2>
1889
- <b><?php echo LM_DATABASE_ARCHIVE; ?></b>
1890
  </th>
1891
- </tr>
1892
- <tr>
1893
- <td><input type="checkbox" id="dbbackup" name="dbbackup" checked value="1" />&nbsp;<?php echo LM_CONFIRM_DATABASE; ?></td>
1894
- </tr>
1895
  <tr>
1896
- <td><input type="checkbox" id="dbbackup_drop" name="dbbackup_drop" value="1" />&nbsp;<?php echo "Add DROP SYNTAX"; ?></td>
 
 
 
 
 
1897
  </tr>
1898
  <tr>
1899
  <td><?php echo "Mysql Compatibility"; ?> &nbsp;
@@ -1908,7 +2444,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
1908
  <?php echo LM_DATABASE_EXCLUDE_TABLES?>
1909
  </th></tr>
1910
  <tr><td>
1911
- <?php echo LM_DATABASE_CURRENT?> <b><?php echo $mosConfig_db;?></b><br />
1912
  <select name='excltables[]' MULTIPLE SIZE=15>
1913
  <?php
1914
 
@@ -1937,7 +2473,8 @@ function showBackups( &$files, &$sizes, $path, $option ) {
1937
 
1938
  while($row = mysql_fetch_array($query)){
1939
 
1940
- echo "<option value='".$row[0]."'>$row[0]</option>";
 
1941
 
1942
  }
1943
 
@@ -1951,6 +2488,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
1951
  ?>
1952
 
1953
  </table>
 
1954
  <?php
1955
  $tabs->endTab();
1956
  }
@@ -1964,7 +2502,7 @@ function showBackups( &$files, &$sizes, $path, $option ) {
1964
  </tr>
1965
  <tr>
1966
  <td>
1967
- <input type=text name='bname' value='' size=40><br/>
1968
  <?php echo LM_BACKUP_NAME_SUB?>
1969
  </td>
1970
  </tr>
@@ -1998,6 +2536,15 @@ function showBackups( &$files, &$sizes, $path, $option ) {
1998
  ?>
1999
 
2000
  </table>
 
 
 
 
 
 
 
 
 
2001
  <?php
2002
  $tabs->endTab();
2003
  $tabs->endPane();
@@ -2078,17 +2625,23 @@ function showBackups( &$files, &$sizes, $path, $option ) {
2078
 
2079
  function showHelp( $option ) {
2080
  ?>
2081
-
2082
- <table border="0" align="center" cellspacing="0" cellpadding="2" width="100%" class="adminform">
2083
- <tr><th>
2084
- <?php echo LM_CREDIT_TOP?>
2085
- </th></tr>
2086
- <tr>
2087
- <td>
2088
- <?php echo LM_CLONER_ABOUT?>
2089
- </td>
2090
- </tr>
2091
- </table>
 
 
 
 
 
 
2092
  <form action="index2.php" name="adminForm" method="post">
2093
  <input type="hidden" name="option" value="<?php echo $option; ?>"/>
2094
  <input type="hidden" name="task" value=""/>
@@ -2103,17 +2656,26 @@ function showBackups( &$files, &$sizes, $path, $option ) {
2103
 
2104
  ?>
2105
 
2106
-
2107
- <table border="0" align="center" cellspacing="0" cellpadding="2" width="100%" class="adminform">
2108
- <tr><th>
2109
- <?php echo LM_RESTORE_TOP?>
2110
- </th></tr>
2111
- <tr>
2112
- <td>
2113
- <?php echo LM_CLONER_RESTORE?>
2114
- </td>
2115
- </tr>
2116
- </table>
 
 
 
 
 
 
 
 
 
2117
  <form action="index2.php" name="adminForm" method="post">
2118
  <input type="hidden" name="option" value="<?php echo $option; ?>"/>
2119
  <input type="hidden" name="task" value=""/>
@@ -2126,18 +2688,26 @@ function showBackups( &$files, &$sizes, $path, $option ) {
2126
  // ----------------------------------------------------------
2127
 
2128
  ?>
2129
-
2130
- <table border="0" align="center" cellspacing="0" cellpadding="2" width="100%" class="adminform">
2131
- <tr><th>
2132
- <?php echo LM_CREDIT_TOP?>
2133
- </th></tr>
2134
- <tr>
2135
- <td>
2136
-
2137
- <?echo LM_CLONER_CREDITS?>
2138
- </td>
2139
- </tr>
2140
- </table>
 
 
 
 
 
 
 
 
2141
  <form action="index2.php" name="adminForm" method="post">
2142
  <input type="hidden" name="option" value="<?php echo $option; ?>"/>
2143
  <input type="hidden" name="task" value=""/>
31
 
32
  function mosTabs($int){
33
 
34
+ echo "<div id=\"tabs\">";
35
 
36
  }
37
 
38
  function startTab($name, $class){
39
 
40
+ echo "<div id=\"tabs-$class\"><p>";
41
 
42
 
43
  }
44
 
45
  function endTab(){
46
 
47
+ echo "</pp></div>";
48
 
49
  }
50
 
63
 
64
  function header(){
65
 
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>
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"
107
 
108
  <tr><td align='center'>
109
 
110
+ <div class="status" >
111
+ <table width='100%' bgcolor='white' class="header">
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>
119
+ </a>
120
+ </td></tr>
121
+ </table>
122
+ </td>
123
+ <td align="right">
124
+ <div id="toolbar" style="display:none">
125
+ <?php
126
+ # Generating the buttons...
127
+ require_once( "toolbar.cloner.php" );
128
+ ?>
129
+ </div>
130
+ </td>
131
  </tr>
132
  </table>
133
+ </div>
134
+
135
  <br />
136
  <table width="100%" cellspacing='3' cellpadding="4" >
137
  <tr><td valign='top' width="160" >
175
  //-->
176
  </script></div> </td></tr></table>
177
 
178
+ <div id="ads" value="display:none";>
179
  <!--XCloner Ads -->
180
  <br />
181
  <table width='100%' cellpadding='5' height='100%' class='menu_table'><tr><td>
200
  </center>
201
  </td></td></table>
202
  <!-- END Ads -->
203
+ </div>
204
+
205
 
206
  </td><td valign='top' align='left' style="padding-left: 20px;">
207
 
209
  <?php
210
  if($_REQUEST['mosmsg']!="")
211
 
212
+ echo "<center><h2>".strip_tags($_REQUEST['mosmsg'])."</h2></center>";
213
 
214
  }
215
 
219
  </td></tr></table>
220
  <hr><br /><br />
221
  <center>
222
+ <p>Powered by <a href='http://www.xcloner.com' target='_blank'>XCloner</a>. Backup and Restore Made Easy!</p></center>
223
 
224
  </td></tr></table>
225
+ <script>
226
+ $( "#toolbar" ).show();
227
+ $( "#ads" ).show();
228
+ </script>
229
+ </body></html>
230
 
231
  <?php
232
 
240
  $backupFile = $f['basename'];
241
 
242
  if (file_exists($filename)) {
243
+ echo "<h2>Initializing backup...</h2>";
244
+ echo "<h3 >Backup <b>$filename</b> created, we may continue!</h3><br />";
245
+
246
  $urlReturn = "index2.php?option=com_cloner&lines=" . $perm_lines . "&task=refresh&backup=$backupFile&excl_manual=$excl_manual";
247
 
248
  if(!$_CONFIG['refresh_mode']){
253
 
254
  }else{
255
 
256
+ echo "<script>var dbbackup = ".intval($_REQUEST['dbbackup']).";</script>";
257
+
258
  ?>
259
  <!--Start ProgressBar-->
260
  <script type="text/javascript">
263
 
264
  var globalUrl;
265
  var step = "r1";
266
+ var count = 0;
267
+ var counter = 0;
268
+ var counter_old = 0;
269
+ var completeSize = 0;
270
+ var oldBackupName = "";
271
+ var parts = 0;
272
+ var oldSize = 0;
273
 
274
  $("#progressbar").progressbar({ value: 0 });
275
 
278
  //reset state here;
279
  $("#error").show();
280
  $("#errorText").append(status+" -- "+error);
281
+ $("#errorText").append("<br /><br />JSON url: "+globalUrl);
282
  }});
283
 
284
+ function getSize(bytes, conv){
285
 
286
+ return (parseInt(bytes)/parseInt(conv)).toFixed(2);
287
+
288
+ }
289
+ function appendIcon(icon){
290
 
291
+ return '<span class="ui-icon ui-icon-'+icon+'" style="float:left;"></span>';
292
+
293
+ }
294
+
295
+ function xclonerRecurseMYSQL(url){
296
+ // create database backup
297
  globalUrl = url;
298
  step = "r1";
299
 
304
  $("#errorText").text(url);
305
  }
306
 
307
+ if(json.dumpsize && !json.endDump){
308
+ $("#mysqlProcess").append(" ("+getSize(json.dumpsize, 1024*1024)+" MB) <br />");
309
+ }
310
+
311
+ if(json.newDump){
312
+ count++;
313
+ //$("#mysqlProcess").append(appendIcon("arrowthick-1-e"));
314
+ if(json.databaseName!="")
315
+ $("#mysqlProcess").append("<b>["+json.databaseName+"]</b> <span id='db"+count+"'></span> tables ");
316
+ counter = parseInt(json.startAtLine);
317
+
318
+ }else{
319
+ $("#db"+count).text(json.startAtLine - counter);
320
+ }
321
+
322
+ if(!parseInt(json.finished)){
323
+ //get next records
324
+
325
+ $("#db"+count).text(json.startAtLine - counter);
326
+
327
+ 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;
328
+ xclonerRecurseMYSQL(recurseUrl);
329
+
330
+ }
331
+ else{
332
+
333
+ $("#fileSystem").show();
334
+ var recurseUrl="index2.php?task=recurse_files&mode=start&nohtml=1";
335
+ xclonerRecurseJSON(recurseUrl);
336
+
337
+ }
338
+
339
+
340
+ });
341
+ }
342
+
343
+ function xclonerRecurseJSON(url){
344
+ //scan file system
345
+ $("#result").hide();
346
+
347
+ globalUrl = url;
348
+ step = "r2";
349
+
350
+ $.getJSON(url, function(json) {
351
+
352
+ if(!json){
353
+ $("#error").show();
354
+ $("#errorText").text(url);
355
+ }
356
+
357
  if(!parseInt(json.finished)){
358
 
359
  $("#recurseStatus").text(json.tfiles);
364
  }
365
  else{
366
  var size = parseFloat(json.size)/(1024*1024);
367
+ $("#recurseStatus").text(" done! (Estimated size:"+size.toFixed(2)+"MB) in "+json.tfiles+" files");
368
  $("#result").show();
369
+
370
+ if(json.overlimit.length > 0){
371
+ $("#overlimit").show();
372
+ for(var i=0; i < json.overlimit.length; i++){
373
+
374
+ $("#overlimit").append("<span class='oversizedFile'></span>"+json.overlimit[i]+"<br />");
375
+
376
+ }
377
+ }
378
+
379
  //xclonerGetJSON("<?php echo $urlReturn;?>");
380
  returnUrl = "index2.php?option=com_cloner&lines="+json.tfiles+"&task=refresh&backup=<?php echo $backupFile; ?>&excl_manual=";
381
  xclonerGetJSON(returnUrl);
387
  }
388
 
389
  function xclonerGetJSON(url){
390
+ //create backup archive
391
  globalUrl = url;
392
+ step = "r3";
393
 
394
  $.getJSON(url, function(json) {
395
 
400
 
401
  var percent = parseInt(json.percent);
402
  $("#progressbar").progressbar({ value: percent });
403
+ $("#backupSize").text(getSize(json.backupSize, 1024*1024));
404
  $("#nFiles").text(json.startf);
405
  $("#percent").text(json.percent);
406
+ $("#backupName").text(json.backup);
407
  if(!json.finished){
408
+
409
+ if(oldBackupName != json.backup){
410
+ oldBackupName = json.backup;
411
+ completeSize = completeSize + oldSize;
412
+ parts++;
413
+ }else{
414
+ oldSize = parseInt(json.backupSize);
415
+ }
416
+
417
  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;
418
  xclonerGetJSON(url);
419
  }else{
420
 
421
+ //all done
422
+ url = "index2.php?task=cleanup&nohtml=1";
423
+ $.getJSON(url, function(json) {
424
+ });
425
+
426
  $("#complete").show();
427
  $("#nFiles").text(json.lines);
428
+ if(parts > 0){
429
+ $("#backupParts").show();
430
+ $("#backupPartsNr").text(parts);
431
  }
432
+ $("#backupFiles").text(json.lines);
433
+ $("#backupSizeComplete").append(getSize(completeSize+parseInt(json.backupSize), 1024*1024));
434
+ $("#backupNameC").text(json.backup);
435
+ $( "#dialog:ui-dialog" ).dialog( "destroy" );
436
+ $( "#dialog-message" ).dialog({
437
+ modal: true,
438
+ width: 600,
439
+ buttons: {
440
+ Close: function() {
441
+ $( this ).dialog( "close" );
442
+ }
443
+ }
444
+ });
445
+
446
+ }
447
 
448
  });
449
 
450
  }
451
 
452
+ //Main program here
453
+
454
  $("#retry").click(function(){
455
  $("#error").hide();
456
  $("#errorText").empty();
457
  if(step == "r1"){
458
+ xclonerRecurseMYSQL(globalUrl);
459
+ }
460
+ else
461
+ if(step == "r2"){
462
  xclonerRecurseJSON(globalUrl);
463
  }
464
+ else if(step == "r3"){
465
  xclonerGetJSON(globalUrl);
466
  }
467
  });
468
 
469
+ $("#result").hide();
470
+ $("#fileSystem").hide();
471
+
472
+ if(dbbackup){
473
+ recurseUrl = "index2.php?task=recurse_database&nohtml=1&dbbackup_comp=<?php echo $_REQUEST['dbbackup_comp']?>&dbbackup_drop=<?php echo $_REQUEST['dbbackup_drop']?>";
474
+ xclonerRecurseMYSQL(recurseUrl);
475
+ }else{
476
+ $("#fileSystem").show();
477
+ var recurseUrl="index2.php?task=recurse_files&mode=start&nohtml=1";
478
+ xclonerRecurseJSON(recurseUrl);
479
 
480
+ }
481
 
482
  });
483
  </script>
484
 
485
+ <?php
 
 
 
 
 
 
 
 
486
 
487
+ if($_REQUEST['dbbackup']){
488
+ //lets start the incremental procedure
489
+ ?>
490
 
491
+ <div id="mysqlBackup">
492
+ <h2>Database backup...</h2><br />
493
+ <div id="mysqlProcess"></div><div id="counter"></div>
494
+ </div>
 
 
495
 
496
+ <?php
497
+ }
498
+ ?>
499
+
500
+ <div id="fileSystem">
501
+ <h2>Filesystem backup...</h2>
502
+
503
+ <div id="recurseFiles">
504
+ <br /><strong>Scanning files system...</strong> <span id="recurseStatus"></span>
505
+ <br /><div id="overlimit" style="display:none"><b>Excluded oversized files:</b><br /> </div>
506
+ </div>
507
+
508
+ <div id="result">
509
+ <br /> <strong>Processing Files:</strong> <span id="percent">0</span>% (<span id="nFiles"></span> files)
510
+ <br /><br /> <strong>Backup Name: </strong><span id="backupName"></span>
511
+ <br /><br /> <strong>Backup Size: </strong><span id="backupSize"></span>MB
512
+ <br /><br /> <div id="progressbar"></div>
513
+ </div>
514
+
515
+ <div id="complete">
516
+ <br /><h2>Backup completed!</h2>
517
+
518
+ <form action="index2.php" name="adminForm" method="post">
519
+ <input type=hidden name=files[1] value='<?php echo $backupFile?>'>
520
+ <input type=hidden name=cid[1] value='<?php echo $backupFile?>'>
521
+ <input type="hidden" name="option" value="<?php echo $option; ?>"/>
522
+ <input type="hidden" name="task" value=""/>
523
+ </form>
524
+
525
+ <div id="dialog-message" title="Backup completed">
526
+ <p>
527
+ <span class="ui-icon ui-icon-arrowthick-1-e" style="float:left;"></span>
528
+ <strong>Backup name:</strong> <span id="backupNameC"></span>
529
+ </p>
530
+ <p>
531
+ <span class="ui-icon ui-icon-arrowthick-1-e" style="float:left;"></span><strong>Backup size:</strong> <span id="backupSizeComplete"></span>MB
532
+ </p>
533
+ <p>
534
+ <span class="ui-icon ui-icon-arrowthick-1-e" style="float:left;"></span><strong>Number of files:</strong> <span id="backupFiles"></span>
535
+ </p>
536
+ <p class="backupParts">
537
+ <span class="ui-icon ui-icon-arrowthick-1-e" style="float:left;"></span><strong>Backup Parts:</strong> <span id="backupPartsNr"></span>
538
+ </p>
539
+ </div>
540
+
541
+ </div>
542
  </div>
543
 
544
  <div id="error" style="display:none;">
587
  }
588
 
589
  function _FDefault(){
590
+ global $_CONFIG, $html;
591
  ?>
592
 
593
  <form action="index2.php" method="post" name="adminForm">
662
  <div class="status">
663
  <span class="mtext">Backup Start Path Check: </span>
664
  <?php
665
+ $html = new HTML_cloner();
666
+ $stat = $html->path_check($_CONFIG[backup_start_path]);
667
 
668
  if( $stat['code'] > 0 and $stat['code'] < 3){
669
  echo "<span class='error'>".$stat['message']; $error = 1;
670
  }
671
  else{
672
  echo "<span class='success'>OK";
673
+ if(!is_dir($_CONFIG[backup_start_path]."/administrator/backups")){
674
+ @mkdir($_CONFIG[backup_start_path]."/administrator");
675
+ if(@mkdir($_CONFIG[backup_start_path]."/administrator/backups"))
676
+ echo "<script>window.location='index2.php'</script";
677
+ }
678
+ }
679
  echo " ($_CONFIG[backup_start_path])";
680
  ?>
681
  </span></div>
682
+
683
  <div class="status">
684
  <span class="mtext">Backup Store Path Check: </span>
685
  <?php
686
 
687
+ $stat = $html->path_check($_CONFIG[backup_store_path]);
688
 
689
  if( $stat['code'] > 0){
690
  echo "<span class='error'>".$stat['message']; $error = 1;
694
  }
695
  echo " ($_CONFIG[backup_store_path])";
696
  ?>
697
+ </span>
698
+ </div>
699
+
700
  <div class="status">
701
  <span class="mtext">Temporary Path Check: </span>
702
  <?php
703
 
704
+ $stat = $html->path_check($_CONFIG[temp_dir]);
705
 
706
  if( $stat['code'] > 0){
707
  echo "<span class='error'>".$stat['message']; $error = 1;
713
  ?>
714
  </span></div>
715
 
716
+ <div class="status">
717
+ <span class="mtext">Authentication: </span>
718
+ <?php
719
+
720
+ if($_CONFIG['jcpass'] == md5('admin')){
721
+ echo "<span class='error'>Change default password 'admin'"; $error = 1;
722
+ }
723
+ else{
724
+ echo "<span class='success'>OK";
725
+ }
726
+
727
+ ?>
728
+ </span></div>
729
+
730
  <div class="status">
731
  <span class="mtext">Backup Ready: </span>
732
  <?php
751
  <?php
752
  }
753
 
754
+ /*The basic Authentication form*/
755
  function Login(){
756
 
757
  ?>
758
  <center><br />
 
 
 
 
 
 
 
 
 
 
 
 
759
 
760
+ <script>
761
+ $(function() {
762
+ $( "#login" ).button({
763
+ icons: {
764
+ primary: "ui-icon-locked"
765
+ }
766
+ })
767
+ $("#login").click(function() {
768
+ $("#adminForm")[0].submit();
769
+ return false;
770
+ })
771
+
772
+ $( "#reset" ).button({
773
+ icons: {
774
+ primary: "ui-icon-trash"
775
+ }
776
+ })
777
+ $( "#reset" ).click(function() {
778
+ $("#username").val('');$("#password").val('');
779
+ return false;
780
+ });
781
+
782
+ });
783
+ </script>
784
+
785
+
786
+ <div class="loginform">
787
+ <form action="index2.php" method="post" name="adminForm" id="adminForm">
788
+ <table class="loginForm">
789
+ <tr><td align='center'>
790
+ <table align='center' cellpadding='10' cellspacing='20'>
791
+ <tr ><td colspan='2' align='center'><b>Authentication Area:</b></td></tr>
792
+ <tr><td>Username:</td><td><input type='text' size='30' name='username' id='username'></td></tr>
793
+ <tr><td>Password:</td><td><input type='password' size='30' name='password' id='password'></td></tr>
794
+ <tr><td>&nbsp;</td><td>
795
+ <div class="loginform">
796
+ <button id="login">Login</button>
797
+ <button id="reset">Reset</button>
798
 
799
 
800
+ </div>
801
+ </td></tr>
802
+ <tr><td colspan='2'><?php echo LM_LOGIN_TEXT;?></td></tr>
803
+ </table>
804
+ </td></tr>
805
  </table>
806
 
807
  <input type="hidden" name="option" value="com_cloner" />
808
+ <input type="hidden" name="task" value="dologin" />
809
  <input type="hidden" name="boxchecked" value="0" />
810
  <input type="hidden" name="hidemainmenu" value="0" />
811
 
818
  function Cron(){
819
  global $_CONFIG;
820
  ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
821
 
822
+ <script>
823
+ $(function() {ret:
824
+ $( "#tabs" ).tabs();
825
+ });
826
+ </script>
827
 
828
+ <div id="tabs">
829
+ <ul>
830
+ <li><a href="#tabs-1"><?php echo LM_CRON_TOP?></a></li>
831
+ </ul>
832
 
833
+ <div id="tabs-1"><p>
834
+
835
+ <div class="mainText">
836
+ <?php echo LM_CRON_SUB?>
837
+ <br /><br />
838
+
839
+ <ul>
840
+ <li><input type="text" value="/usr/bin/php <?php echo dirname(__FILE__);?>/cloner.cron.php" size="150" /></li>
841
+ <li><strong>curl http://website/path_to_xcloner_folder/cloner.cron.php</strong></li>
842
+ <li><strong>wget -q http://website/path_to_xcloner_folder/cloner.cron.php</strong></li>
843
+ <li><strong>lynx -sourcehttp://website/path_to_xcloner_folder/cloner.cron.php</strong></li>
844
+ </ul>
845
+ <br /><br />
846
+
847
+ For <b>Running Multiple Crons</b>, you need to first create a custom configuration file in the XCloner Configuration -> Cron tab
848
+ and then replace "cloner.cron.php" with "cloner.cron.php?config=myconfig.php", only use 'links' or 'lynx' options to run the cronjob
849
+ <br /><br />
850
+
851
+ If you would like to use the <b>php SSH command</b> for running Multiple Crons, you will need to replace
852
+ the "cloner.cron.php" with <b>"cloner.cron.php myconfig.php"</b> in the command line.
853
+ <br /><br />
854
+
855
+ <?php echo LM_CRON_HELP?>
856
+ </div>
857
+
858
+ </p></div>
859
+ </div>
860
 
861
  <?php
862
  }
990
  global $_CONFIG;
991
 
992
  ?>
993
+ <script>
994
+ $(function() {
995
+ $( "#toggle" ).button();
996
+ $( "#toggle" ).click(function() { checkJAll(<?php echo count( $lang_arr ); ?>, "toggle", "cb"); });
997
+ $( "#checklist" ).buttonset();
998
+ });
999
+ </script>
1000
 
1001
+ <form action="index2.php" method="post" name="adminForm">
1002
+ <div id="checklist">
1003
  <table class="adminlist">
1004
  <tr>
1005
+ <th align="center">
1006
+ <input id="toggle" type="checkbox" name="toggle" value="" /><label for="toggle">Check All</label>
 
1007
  </th>
1008
  <th align="left">
1009
  <?php echo LM_LANG_NAME ?>
1010
  </th>
1011
  </tr>
 
1012
 
1013
+ <?php
1014
  for($i=0; $i<sizeof($lang_arr); $i++){
1015
 
1016
  ?>
1017
 
1018
  <tr>
1019
+ <!--<td width="5" align="left"><?php echo ($i+1);?></td>-->
1020
+ <td align="center" width="100">
1021
+ <label for="cb<?php echo $i ?>"><?php echo $i ?></label>
1022
+ <input type="checkbox" id="cb<?php echo $i ?>" name="cid[<?php echo $i?>]" value="<?php echo $i ?>" />
1023
+ <input type="hidden" name="files[<?php echo $i?>]" value="<?php echo $lang_arr[$i] ?>" />
1024
  </td>
1025
  <td align="left" >
1026
  <a href="index2.php?option=<?php echo $option;?>&task=edit_lang&langx=<?php echo $lang_arr[$i];?>"><?php echo ucfirst($lang_arr[$i])?>
1030
 
1031
  }
1032
  ?>
1033
+ </table></div>
1034
  <input type="hidden" name="option" value="com_cloner" />
1035
  <input type="hidden" name="task" value="lang" />
1036
  <input type="hidden" name="boxchecked" value="0" />
1046
  global $baDownloadPath, $_CONFIG;
1047
 
1048
  ?>
1049
+
1050
+ <script type="text/javascript">
1051
+
1052
+ $(function() {
1053
+ $( "#toggle" ).button();
1054
+ $( "#toggle" ).click(function() { checkJAll(<?php echo (count( $files )); ?>, "toggle", "cb"); });
1055
+ $( "#checklist" ).buttonset();
1056
+
1057
+ $( "#Clone, #Rename, #Delete, #Move" ).unbind("click");
1058
+ $( "#Clone, #Rename, #Delete, #Move" ).click(function(){
1059
+ if(!$("input:checked").length){
1060
+
1061
+ $( "#error-message" ).dialog({
1062
+ width: 500,
1063
+ height: 200,
1064
+ modal: true,
1065
+ buttons: {
1066
+ Ok: function() {
1067
+ $( this ).dialog( "close" );
1068
+ }
1069
+ }
1070
+ });
1071
+
1072
+ return false;
1073
+ }else{
1074
+ var action = $(this).attr('id').toLowerCase();
1075
+ document.adminForm.task.value=action;
1076
+ document.adminForm.submit();
1077
+ }
1078
+ })
1079
+
1080
+
1081
+ })
1082
+ </script>
1083
+
1084
+ <div id="error-message" title="Error" style="display:none;">
1085
+ <p>
1086
+ <span class="ui-icon ui-icon-circle-check" style="float:left; margin:0 7px 50px 0;"></span>
1087
+ Please select at least one backup archive.
1088
+ </p>
1089
+
1090
+ </div>
1091
+ <div id="checklist">
1092
  <form action="index2.php" method="post" name="adminForm">
1093
  <table class="adminlist">
1094
  <tr>
1095
+ <th width="100">
1096
+ <input type="checkbox" id="toggle" name="toggle" value="" /><label for="toggle">Check All</label>
 
 
 
 
1097
  </th>
1098
+ <th align="left" width="100px;">
1099
  <?php echo LM_COL_DOWNLOAD ?>
1100
  </th>
1101
+ <th width="50%" class="title">
1102
+ <?php echo LM_COL_FILENAME ?>
1103
+ </th>
1104
  <th align="left" width="10%">
1105
  <?php echo LM_COL_SIZE ?>
1106
  </th>
1107
+ <th align="left" width="">
1108
  <?php echo LM_COL_DATE ?>
1109
  </th>
1110
  </tr>
1112
  $k = 0;
1113
  for ($i=0; $i <= (count( $files )-1); $i++) {
1114
  $date = date ("D jS M Y H:i:s (\G\M\T O)", filemtime($path.'/'.$files[$i]));
1115
+ $url = "index2.php?option=com_cloner&task=download&file=".'/'.urlencode($files[$i]);
1116
  ?>
1117
  <tr class="<?php echo "row$k"; ?>">
1118
+
 
 
1119
  <td align="center">
1120
+ <label for="cb<?php echo $i ?>"><?php echo $i ?></label>
1121
+ <input type="checkbox" id="cb<?php echo $i ?>" name="cid[<?php echo $i?>]" value="<?php echo $i ?>" />
1122
+ <input type="hidden" name="files[<?php echo $i?>]" value="<?php echo $files[$i] ?>" />
 
 
1123
  </td>
1124
  <td align="left">
1125
+ <a target='_blank' href="<?php echo $url ?>"><img src="images/filesave.png" border="0" title="<?php echo LM_DOWNLOAD_TITLE." - ".$files[$i] ?>" /></a>
1126
+ </td>
1127
+ <td>
1128
+ <span class="backup_name"><?php echo $files[$i]; ?></span>
1129
+ <input type="hidden" id="f<?php echo $i ?>" name="f<?php echo $i ?>" value="<?php echo $files[$i]; ?>" >
1130
+ </td>
1131
+
 
 
 
 
 
 
 
1132
  <td align="left">
1133
+ <?php echo $sizes[$i]; ?>
1134
  </td >
1135
  <td align="left">
1136
+ <?php echo $date; ?>
1137
  </td>
1138
  </tr>
1139
  <?php
1141
  }
1142
  ?>
1143
  </table>
1144
+ </div>
1145
  <input type="hidden" name="option" value="com_cloner" />
1146
  <input type="hidden" name="task" value="" />
1147
  <input type="hidden" name="boxchecked" value="0" />
1155
  global $config_file,$_CONFIG, $lang_array, $database, $mosConfig_db;
1156
  ?>
1157
  <form name='adminForm' action='index2.php' method='POST'>
1158
+
1159
+ <script>
1160
+ $(function() {
1161
+ $( "#tabs" ).tabs();
1162
+ });
1163
+
1164
+ $(function() {
1165
+ $( "#radiog1" ).buttonset();
1166
+ $( "#radiog2" ).buttonset();
1167
+ $( "#radiog3" ).buttonset();
1168
+ $( "#radiog4" ).buttonset();
1169
+ $( "#radio" ).buttonset();
1170
+ $( "#radiom" ).buttonset();
1171
+ $( "#radiob" ).buttonset();
1172
+ $( "#radioftp" ).buttonset();
1173
+ $( "#radioftps" ).buttonset();
1174
+ $( "#radiodebug" ).buttonset();
1175
+ $( "#radiorefresh" ).buttonset();
1176
+ $( "#checktar" ).button();
1177
+ $( "#cron_file_delete_act" ).button();
1178
+ $( "#cron_sql_drop" ).button();
1179
+ $( "#cron_amazon_active" ).button();
1180
+ $( "#cron_dropbox_active").button();
1181
+ $( "#cron_amazon_ssl" ).button();
1182
+ $( "#cron_ftp_delb" ).button();
1183
+ $( "#checkmysqldump" ).button();
1184
+ });
1185
+ </script>
1186
+
1187
+ <?php $tabs = new mosTabs(1);?>
1188
+ <ul>
1189
+
1190
+ <li><a href="#tabs-1"><?php echo LM_TAB_GENERAL;?></a></li>
1191
+ <li><a href="#tabs-2"><?php echo LM_TAB_MYSQL;?></a></li>
1192
+ <li><a href="#tabs-3"><?php echo LM_TAB_AUTH;?></a></li>
1193
+ <li><a href="#tabs-4"><?php echo LM_TAB_SYSTEM;?></a></li>
1194
+ <li><a href="#tabs-5"><?php echo LM_TAB_CRON;?></a></li>
1195
+ <li><a href="#tabs-6"><?php echo LM_TAB_INFO;?></a></li>
1196
+ </ul>
1197
+
1198
  <table class='adminform'>
1199
  <tr><th colspan='2'>
1200
  <?php echo LM_CONFIG_EDIT?> <?php echo $config_file?>
1201
  </th></tr>
1202
  </table>
1203
  <?php
1204
+ $tabs->startTab(LM_TAB_GENERAL,"1");
 
1205
  ?>
 
1206
 
1207
+ <div id="configtabinside">
1208
+
1209
+ <div>
1210
+ <h3><a href="#"> <?php echo LM_CONFIG_BSETTINGS?></a></h3>
1211
+ <div><p>
1212
+ <table class='adminform'>
1213
+
1214
+ <tr>
1215
+ <td>
1216
+ <?php echo LM_CONFIG_UBPATH?>
1217
+ </td>
1218
+ <td>
1219
+ <input type=text size=100 name='backup_path' value='<?php echo $_CONFIG[backup_path]?>'>
1220
+ <br /><?php echo LM_CONFIG_UBPATH_SUB?>
1221
+ </td>
1222
+ </tr>
1223
+
1224
+ <tr>
1225
+ <td width='250'>
1226
+ <?php echo LM_CONFIG_BPATH?>
1227
+ </td>
1228
+ <td>
1229
+ <input type=text size=100 name='clonerPath' value='<?php echo $_CONFIG[clonerPath]?>'>
1230
+ <br /><?php echo LM_CONFIG_BPATH_SUB?>
1231
+ </td>
1232
+ </tr>
1233
+
1234
+ </table>
1235
+ </p></div>
1236
+ </div>
1237
+
1238
+ <div>
1239
+ <h3><a href="#"> <?php echo LM_CONFIG_BSETTINGS_OPTIONS?></a></h3>
1240
+ <div><p>
1241
+ <table class='adminform'>
1242
+
1243
+ <tr>
1244
+ <td width='250'>
1245
+ <?php echo LM_CONFIG_MANUAL_BACKUP;?>
1246
+ </td>
1247
+ <td>
1248
+ <div id="radiog1">
1249
+ <label for="radiog11"><?php echo LM_YES?></label> <input id="radiog11" type=radio size=50 value=1 name='backup_refresh' <?php if($_CONFIG[backup_refresh]==1) echo 'checked';?>>
1250
+ <label for="radiog12"><?php echo LM_NO?></label> <input id="radiog12" type=radio size=50 value=0 name='backup_refresh' <?php if($_CONFIG[backup_refresh]==0) echo 'checked';?>>
1251
+ <br><small><?php echo LM_CONFIG_MANUAL_BACKUP_SUB?></small>
1252
+ </div>
1253
+ </td>
1254
+ </tr>
1255
+
1256
+
1257
+
1258
+ <tr>
1259
+ <td>
1260
+ <?php echo LM_CRON_DB_BACKUP?>
1261
+ </td>
1262
+ <td>
1263
+ <div id="radiog3">
1264
+ <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';?>>
1265
+ <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';?>>
1266
+ <br /><?php echo LM_CRON_DB_BACKUP_SUB?>
1267
+ </div>
1268
+
1269
+ </td>
1270
+ </tr>
1271
+
1272
+ <tr>
1273
+ <td>
1274
+ <?php echo LM_CONFIG_SYSTEM_MBACKUP?>
1275
+ </td>
1276
+ <td>
1277
+ <div id="radiog4">
1278
+ <label for="radiog41">Yes</label> <input id="radiog41" type=radio size=50 value=1 name='add_backups_dir' <?php if($_CONFIG[add_backups_dir]==1) echo 'checked';?>>
1279
+ <label for="radiog42">No</label> <input id="radiog42" type=radio size=50 value=0 name='add_backups_dir' <?php if($_CONFIG[add_backups_dir]==0) echo 'checked';?>>
1280
+ <br /><?php echo LM_CONFIG_SYSTEM_MBACKUP_SUB?>
1281
+ </td>
1282
+ </div>
1283
+ </tr>
1284
+
1285
+ </table>
1286
+ </p></div>
1287
+ </div>
1288
+
1289
+ <div>
1290
+ <h3><a href="#"> <?php echo LM_CONFIG_BSETTINGS_SERVER?></a></h3>
1291
+ <div><p>
1292
+ <table class='adminform'>
1293
+
1294
+ <tr><td width='250'>
1295
+ <?php echo LM_CONFIG_MEM?>
1296
+ </td>
1297
+ <td align='left'>
1298
+ <table style="width:auto; margin-bottom: 10px;" cellpadding='0' cellspacing='2' border='1'>
1299
+ <tr bgcolor='#efefef'><td style="width:70px;">
1300
+ <label for="checktar"><?php echo LM_ACTIVE;?></label> <input type=checkbox id="checktar" value=1 name='mem' <?php if($_CONFIG[mem]==1) echo 'checked';?>>
1301
+ </td><td align='left'>
1302
+
1303
+ <table width='100%' cellpadding='0' cellspacing='0'>
1304
+ <tr><td>
1305
+ <?php echo LM_TAR_PATH;?> <br /><input size='50' type=text name=tarpath value='<?php echo $_CONFIG[tarpath]?>'><br />
1306
+ <?php echo LM_TAR_PATH_SUB;?>
1307
+ </td></tr>
1308
+
1309
+ </table>
1310
+
1311
+
1312
+ </td></tr>
1313
+
1314
+ <tr bgcolor='#dedede'><td>
1315
+ <label for="checkmysqldump"><?php echo LM_ACTIVE?></label> <input id="checkmysqldump" type=checkbox value=1 name='sql_mem' <?php if($_CONFIG[sql_mem]==1) echo 'checked';?>>
1316
+ </td><td align='left'>
1317
+ <?php echo LM_MYSQLDUMP_PATH;?> <br /><input type=text size='50' name='sqldump' value='<?php echo $_CONFIG[sqldump]?>'>
1318
+
1319
+ </td></tr>
1320
+ </table>
1321
+
1322
+ <?php echo LM_CONFIG_MEM_SUB?>
1323
+
1324
+ </td>
1325
+ </tr>
1326
+ </table>
1327
+ </p></div>
1328
+ </div>
1329
+
1330
+ <div>
1331
+ <h3><a href="#">Public Key Management</a></h3>
1332
+ <div><p>
1333
+ <table class='adminForm'>
1334
+
1335
+ <tr><td width="250">
1336
+ Public Key
1337
+ </td>
1338
+ <td>
1339
+ <input type-text size=50 name='license_code' value="<?php echo $_CONFIG[license_code]?>"/>
1340
+ <br />Use this code in the MultiSite XCloner Manager <a target='_blank' href='http://www.xcloner.com/'>XCloner.com Members area</a>
1341
+ <br />Leave it empty to disable it
1342
+
1343
+ </td>
1344
+ </tr>
1345
+
1346
+ </table>
1347
+ </p></div>
1348
+ </div>
1349
+
1350
+ </div>
1351
 
1352
+ <?php
1353
+ $tabs->endTab();
1354
+ $tabs->startTab(LM_TAB_MYSQL,"2");
1355
+ ?>
1356
+ <div id="configtabinside">
1357
+ <div>
1358
+ <h3><a href="#"><?php echo LM_CONFIG_MYSQL?></a></h3>
1359
+ <div><p>
1360
+
1361
+ <table class='adminform'>
1362
+
1363
+ <tr>
1364
+ <td width='250'>
1365
+ <?php echo LM_CONFIG_MYSQLH?>
1366
+ </td>
1367
+ <td>
1368
+ <input type=text size=50 name='mysql_host' value='<?php echo $_CONFIG[mysql_host]?>'>
1369
+ <br /><?php echo LM_CONFIG_MYSQLH_SUB?>
1370
+ </td>
1371
+ </tr>
1372
+
1373
+ <tr>
1374
+ <td>
1375
+ <?php echo LM_CONFIG_MYSQLU?>
1376
+ </td>
1377
+ <td>
1378
+ <input type=text size=50 name='mysql_user' value='<?php echo $_CONFIG[mysql_user]?>'>
1379
+ <br /><?php echo LM_CONFIG_MYSQLU_SUB?>
1380
+ </td>
1381
+ </tr>
1382
+
1383
+ <tr>
1384
+ <td>
1385
+ <?php echo LM_CONFIG_MYSQLP?>
1386
+ </td>
1387
+ <td>
1388
+ <input type=text size=50 name='mysql_pass' value='<?php echo $_CONFIG[mysql_pass]?>'>
1389
+ <br /><?php echo LM_CONFIG_MYSQLP_SUB?>
1390
+ </td>
1391
+ </tr>
1392
+
1393
+ <tr>
1394
+ <td>
1395
+ <?php echo LM_CONFIG_MYSQLD?>
1396
+ </td>
1397
+ <td>
1398
+ <input type=text size=50 name='mysql_database' value='<?php echo $_CONFIG[mysql_database]?>'>
1399
+ <br /><?php echo LM_CONFIG_MYSQLD_SUB?>
1400
+ </td>
1401
+ </tr>
1402
+
1403
+ <tr>
1404
+ <td width='200'>
1405
+ <?php echo LM_CONFIG_SYSTEM_MDATABASES?>
1406
+ </td>
1407
+ <td>
1408
+ <div id="radiom">
1409
+ <label for="radiom1"><?php echo LM_YES?></label> <input id="radiom1" type=radio name='system_mdatabases' value='0' <?php if(abs($_CONFIG[system_mdatabases])==0) echo "checked";?>>
1410
+ <label for="radiom2"><?php echo LM_NO?></label> <input id="radiom2" type=radio name='system_mdatabases' value='1' <?php if(abs($_CONFIG[system_mdatabases])==1) echo "checked";?>>
1411
+ <br /> <?php echo LM_CONFIG_SYSTEM_MDATABASES_SUB?>
1412
+ </div>
1413
+ </td>
1414
+ </tr>
1415
+
1416
+ </table>
1417
+ </p></div>
1418
+ </div>
1419
+ </div>
1420
+ <?php
1421
+ $tabs->endTab();
1422
+ $tabs->startTab(LM_TAB_AUTH,"3");
1423
+ ?>
1424
+ <div id="configtabinside">
1425
+ <div>
1426
+ <h3><a href="#"><?php echo LM_CONFIG_AUTH?></a></h3>
1427
+ <div><p>
1428
+ <table class='adminform'>
1429
+ <tr>
1430
+ <td width='250'>
1431
+ <?php echo LM_CONFIG_AUTH_USER?>
1432
+ </td>
1433
+ <td>
1434
+ <input type=text size=30 name='jcuser' value='<?php echo $_CONFIG[jcuser]?>'>
1435
+ <br /><?php echo LM_CONFIG_AUTH_USER_SUB?>
1436
+ </td>
1437
+ </tr>
1438
+
1439
+ <tr>
1440
+ <td>
1441
+ <?php echo LM_CONFIG_AUTH_PASS?>
1442
+ </td>
1443
+ <td>
1444
+ <input type=text size=30 name='jcpass' value=''> <?php if($_CONFIG['jcpass'] == md5('admin')) echo "<font color=red>please change the default password 'admin'</font>"?>
1445
+ <br /><?php echo LM_CONFIG_AUTH_PASS_SUB?>
1446
+ </td>
1447
+ </tr>
1448
+ </table>
1449
+ </p></div>
1450
+ </div>
1451
+ </div>
1452
+ <?php
1453
+ $tabs->endTab();
1454
+ $tabs->startTab(LM_TAB_SYSTEM,"4");
1455
+ ?>
1456
 
1457
+ <div id="configtabinside">
1458
+ <div>
1459
+ <h3><a href="#"><?php echo LM_CONFIG_DISPLAY?></a></h3>
1460
+ <div><p>
1461
+ <table class='adminform'>
1462
+ <tr>
1463
+ <td width='250'>
1464
+ <?php echo LM_CONFIG_SYSTEM_LANG?>
1465
+ </td><td>
1466
+ <select name='select_lang'>
1467
+ <option value=''><?php echo LM_CONFIG_SYSTEM_LANG_DEFAULT;?></option>
1468
+ <?php
1469
+ foreach($lang_array as $value)
1470
+ if($_CONFIG['select_lang'] == $value)
1471
+ echo "<option value='$value' selected>$value</option>\n";
1472
+ else
1473
+ echo "<option value='$value'>$value</option>\n";
1474
+ ?>
1475
+ </select>
1476
+ <br>
1477
+ <br /><?php echo LM_CONFIG_SYSTEM_LANG_SUB?>
1478
+ </td></tr>
1479
+ </table>
1480
+ </p></div>
1481
+ </div>
1482
+ <div>
1483
+ <h3><a href="#"> <?php echo LM_CONFIG_SYSTEM?></a></h3>
1484
+ <div><p>
1485
+
1486
+ <table class='adminform'>
1487
+
1488
+ <tr>
1489
+ <td width='250'>
1490
+ <?php echo LM_CONFIG_SYSTEM_FTP?>
1491
+ </td>
1492
+ <td>
1493
+ <div id="radioftp">
1494
+ <label for="radioftp1">Direct</label><input id="radioftp1" type=radio name='system_ftptransfer' value='0' <?php if(abs($_CONFIG[system_ftptransfer])==0) echo "checked";?>>
1495
+ <label for="radioftp2">Passive</label><input id="radioftp2" type=radio name='system_ftptransfer' value='1' <?php if(abs($_CONFIG[system_ftptransfer])==1) echo "checked";?>> <br>
1496
+ <br /><?php echo LM_CONFIG_SYSTEM_FTP_SUB?>
1497
+ </div>
1498
+
1499
+ </td></tr>
1500
+ <tr><td>
1501
+ <?php echo LM_FTP_TRANSFER_MORE?>
1502
+ </td><td>
1503
+ <div id="radioftps">
1504
+ <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';?>>
1505
+ <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';?>>
1506
+ </td>
1507
+ </tr>
1508
+
1509
+ </table>
1510
+ </p></div>
1511
+ </div>
1512
+ <div>
1513
+ <h3><a href="#"> <?php echo LM_CONFIG_MANUAL?></a></h3>
1514
+ <div><p>
1515
+
1516
+ <script>
1517
+ $(function() {
1518
+ $( "#slider" ).slider({
1519
+ value:parseInt(<?php echo $_CONFIG[backup_refresh_number];?>),
1520
+ min: 10,
1521
+ max: 1000,
1522
+ step: 10,
1523
+ slide: function( event, ui ) {
1524
+ $( "#backup_refresh_number" ).val( ui.value );
1525
+ }
1526
+ });
1527
+ $( "#backup_refresh_number" ).val( $( "#slider" ).slider( "value" ) );
1528
+ });
1529
+ $(function() {
1530
+ $( "#sliderRPS" ).slider({
1531
+ value:parseInt(<?php echo $_CONFIG[recordsPerSession];?>),
1532
+ min: 100,
1533
+ max: 100000,
1534
+ step: 100,
1535
+ slide: function( event, ui ) {
1536
+ $( "#recordsPerSession" ).val( ui.value );
1537
+ }
1538
+ });
1539
+ $( "#recordsPerSession" ).val( $( "#sliderRPS" ).slider( "value" ) );
1540
+ });
1541
+ $(function() {
1542
+ $( "#sliderEFZ" ).slider({
1543
+ value:parseInt(<?php echo $_CONFIG[excludeFilesSize];?>),
1544
+ min: -1,
1545
+ max: 10240,
1546
+ step: 1,
1547
+ slide: function( event, ui ) {
1548
+ $( "#excludeFilesSize" ).val( ui.value );
1549
+ }
1550
+ });
1551
+ $( "#excludeFilesSize" ).val( $( "#sliderEFZ" ).slider( "value" ) );
1552
+ });
1553
+
1554
+ $(function() {
1555
+ $( "#sliderSBS" ).slider({
1556
+ value:parseInt(<?php echo $_CONFIG[splitBackupSize];?>),
1557
+ min: -1,
1558
+ max: 10000,
1559
+ step: 1,
1560
+ slide: function( event, ui ) {
1561
+ $( "#splitBackupSize" ).val( ui.value );
1562
+ }
1563
+ });
1564
+ $( "#splitBackupSize" ).val( $( "#sliderSBS" ).slider( "value" ) );
1565
+ });
1566
+ </script>
1567
+
1568
+ <table class='adminform'>
1569
+
1570
+ <tr><td width="250">
1571
+ <?php echo LM_CONFIG_MANUAL_FILES;?>
1572
+ </td><td>
1573
+ <div class="sliderContainer">
1574
+ <div id="slider" style="width:500px;padding:5px 0 0 0;float:left"></div>
1575
+ <label for="backup_refresh_number"></label>
1576
+ <input id="backup_refresh_number" type=text size=10 name='backup_refresh_number' value=<?php echo $_CONFIG[backup_refresh_number];?>>
1577
+ </div>
1578
+ </td></tr>
1579
+
1580
+ <tr><td width="250">
1581
+ <?php echo LM_CONFIG_DB_RECORDS;?>
1582
+ </td><td>
1583
+ <div class="sliderContainer">
1584
+ <div id="sliderRPS" style="width:500px;padding:5px 0 0 0;float:left;"></div>
1585
+ <label for="recordsPerSession"></label>
1586
+ <input id="recordsPerSession" type=text size=10 name='recordsPerSession' value=<?php echo $_CONFIG[recordsPerSession];?>>
1587
+ </div>
1588
+ </td></tr>
1589
+
1590
+ <tr><td width="250">
1591
+ <?php echo LM_CONFIG_EXCLUDE_FILES_SIZE;?>
1592
+ </td><td>
1593
+ <div class="sliderContainer">
1594
+ <div id="sliderEFZ" style="width:500px;padding:5px 0 0 0;float:left"></div>
1595
+ <label for="excludeFilesSize"></label>
1596
+ <input id="excludeFilesSize" type=text size=10 name='excludeFilesSize' value=<?php echo $_CONFIG[excludeFilesSize];?>> MB
1597
+ </div>
1598
+ </td></tr>
1599
+
1600
+ <tr><td width="250">
1601
+ <?php echo LM_CONFIG_SPLIT_BACKUP_SIZE;?>
1602
+ </td><td>
1603
+ <div class="sliderContainer">
1604
+ <div id="sliderSBS" style="width:500px;padding:5px 0 0 0;float:left;"></div>
1605
+ <label for="splitBackupSize"></label>
1606
+ <input id="splitBackupSize" type=text size=10 name='splitBackupSize' value=<?php echo $_CONFIG[splitBackupSize];?>> MB
1607
+ </div>
1608
+
1609
+ </td></tr>
1610
+
1611
+ <tr><td>
1612
+ <?php echo LM_CONFIG_MANUAL_REFRESH;?>
1613
+ </td><td>
1614
+ <input type=text size=20 name='refresh_time' value=<?php echo $_CONFIG[refresh_time];?>> miliseconds
1615
+
1616
+ </td></tr>
1617
+
1618
+ <tr>
1619
+ <td>
1620
+ <?php echo LM_CRON_COMPRESS?>
1621
+ </td>
1622
+ <td>
1623
+ <div id="radiog2">
1624
+ <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';?>>
1625
+ <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';?>>
1626
+ <br /> <small>Note: this option might break your backup process if the Manual backup option is also enabled</small>
1627
+ </div>
1628
+ </td>
1629
+ </tr>
1630
+
1631
+ <tr><td>
1632
+ <?php echo LM_REFRESH_MODE?>
1633
+ </td><td>
1634
+ <div id="radiorefresh">
1635
+ <label for="radiorefresh1">Normal</label> <input id="radiorefresh1" type=radio size=50 value=0 name='refresh_mode' <?php if($_CONFIG[refresh_mode]==0) echo 'checked';?>>
1636
+ <label for="radiorefresh2">AJAX</label> <input id="radiorefresh2" type=radio size=50 value=1 name='refresh_mode' <?php if($_CONFIG[refresh_mode]==1) echo 'checked';?>>
1637
+ </div>
1638
+ </td></tr>
1639
+
1640
+ <tr><td>
1641
+ <?php echo LM_DEBUG_MODE?>
1642
+ </td><td>
1643
+ <div id="radiodebug">
1644
+ <label for="radiodebug1">No</label> <input id="radiodebug1" type=radio size=50 value=0 name='debug' <?php if($_CONFIG[debug]==0) echo 'checked';?>>
1645
+ <label for="radiodebug2">Yes</label> <input id="radiodebug2" type=radio size=50 value=1 name='debug' <?php if($_CONFIG[debug]==1) echo 'checked';?>>
1646
+ </td></tr>
1647
+ </table>
1648
+
1649
+ </p></div>
1650
+ </div>
1651
 
1652
+ </div>
1653
+ <?php
1654
+ $tabs->endTab();
1655
+ $tabs->startTab(LM_TAB_CRON,"5");
1656
+ ?>
1657
+ <div id="configtabinside">
1658
+
1659
+ <div>
1660
+ <h3><a href="#"> <?php echo LM_CRON_SETTINGS_M?> - all configs are saved in directory configs/ </a></h3>
1661
+ <div><p>
1662
+ <table class='adminform'>
1663
+
1664
+ <tr>
1665
+ <td width='250'>
1666
+ <?php echo LM_CRON_MCRON?>
1667
+ </td>
1668
+ <td>
1669
+ <input type=text size=30 value="<?php echo $_CONFIG[cron_save_as]?>" name='cron_save_as' >.php <br />
1670
+ <?php echo LM_CRON_MCRON_SUB?>
1671
+ </td>
1672
+ </tr>
1673
+
1674
+ <tr>
1675
+ <td>
1676
+ <?php echo LM_CRON_MCRON_AVAIL?>
1677
+ </td>
1678
+ <td>
1679
+ <?php
1680
+
1681
+ if ($handle = @opendir($_CONFIG['multiple_config_dir'])) {
1682
+
1683
+ while (false !== ($file = readdir($handle))) {
1684
+ if( ($file!=".") && ($file!="..") &&($file!="") && (strstr($file, '.php'))){
1685
+ $fcron = "cloner.cron.php?config=$file";
1686
+
1687
+ echo "<b>$fcron</b>";
1688
+
1689
+ echo " - <a href='$fcron' target='_blank'>execute cron</a>";
1690
+
1691
+ echo " | <a href='index2.php?option=com_cloner&task=cron_delete&fconfig=$file'>delete config</a>";
1692
+
1693
+ echo "\n<br />";
1694
+ }
1695
+ }
1696
+
1697
+ closedir($handle);
1698
+ }
1699
+ ?>
1700
+ </td>
1701
+ </tr>
1702
+ </table>
1703
+ </p></div>
1704
+ </div>
1705
+
1706
+ <div>
1707
+ <h3><a href="#"> <?php echo LM_CRON_SETTINGS?></a></h3>
1708
+ <div><p>
1709
+ <table class='adminform'>
1710
+
1711
+ <tr>
1712
+ <td width='250'>
1713
+ <?php echo LM_CRON_SEMAIL?>
1714
+ </td>
1715
+ <td>
1716
+ <input type=text size=30 value="<?php echo $_CONFIG[cron_logemail]?>" name='cron_logemail' > <br />
1717
+ <?php echo LM_CRON_SEMAIL_SUB?>
1718
+ </td>
1719
+ </tr>
1720
+
1721
+ <tr>
1722
+ <td width='250'>
1723
+ <?php echo LM_CRON_FROMEMAIL?>
1724
+ </td>
1725
+ <td>
1726
+ <input type=text size=30 value="<?php echo $_CONFIG[cron_fromlogemail]?>" name='cron_fromlogemail' > <br />
1727
+ <?php echo LM_CRON_FROMEMAIL_SUB?>
1728
+ </td>
1729
+ </tr>
1730
+
1731
+ <tr>
1732
+ <td>
1733
+ <?php echo LM_CRON_MODE?>
1734
+ </td>
1735
+ <td>
1736
+
1737
+ <div id="radio">
1738
+ <input id="radio1" type=radio size=50 value=0 name='cron_send' <?php if($_CONFIG[cron_send]==0) echo 'checked';?>>
1739
+ <label for="radio1"><?php echo LM_CONFIG_CRON_LOCAL?></label>
1740
+ <input id="radio2" type=radio size=50 value=1 name='cron_send' <?php if($_CONFIG[cron_send]==1) echo 'checked';?>>
1741
+ <label for="radio2"><?php echo LM_CONFIG_CRON_REMOTE?></label>
1742
+ <input id="radio3" type=radio size=50 value=2 name='cron_send' <?php if($_CONFIG[cron_send]==2) echo 'checked';?>>
1743
+ <label for="radio3"><?php echo LM_CONFIG_CRON_EMAIL?></label>
1744
+ </div>
1745
+ <?php echo LM_CRON_MODE_INFO?>
1746
+ </td>
1747
+ </tr>
1748
+
1749
+
1750
+ <tr>
1751
+ <td>
1752
+ <?php echo LM_CRON_TYPE?>
1753
+ </td>
1754
+ <td>
1755
+ <div id="radiob">
1756
+ <input id="radiob1" type=radio size=50 value=0 name='cron_btype' <?php if($_CONFIG[cron_btype]==0) echo 'checked';?>>
1757
+ <label for="radiob1"><?php echo LM_CONFIG_CRON_FULL?></label>
1758
+ <input id="radiob2" type=radio size=50 value=1 name='cron_btype' <?php if($_CONFIG[cron_btype]==1) echo 'checked';?>>
1759
+ <label for="radiob2"><?php echo LM_CONFIG_CRON_FILES?></label>
1760
+ <input id="radiob3" type=radio size=50 value=2 name='cron_btype' <?php if($_CONFIG[cron_btype]==2) echo 'checked';?>>
1761
+ <label for="radiob3"><?php echo LM_CONFIG_CRON_DATABASE?></label>
1762
+ <?php echo LM_CRON_TYPE_INFO?>
1763
+ </div>
1764
+ </td>
1765
+ </tr>
1766
+
1767
+ <tr>
1768
+ <td>
1769
+ <?php echo LM_CRON_BNAME?>
1770
+ </td>
1771
+ <td>
1772
+ <input type=text size=50 value="<?php echo $_CONFIG[cron_bname]?>" name='cron_bname' > <br />
1773
+ <?php echo LM_CRON_BNAME_SUB?>
1774
+ </td>
1775
+ </tr>
1776
+
1777
+
1778
+ <tr>
1779
+ <td>
1780
+ <?php echo LM_CRON_IP?>
1781
+ </td>
1782
+ <td>
1783
+ <textarea type=text size=50 name='cron_ip' cols='30' rows='5'><?php echo $_CONFIG[cron_ip]?></textarea> <br />
1784
+ <?php echo LM_CRON_IP_SUB?>
1785
+ </td>
1786
+ </tr>
1787
+ </table>
1788
+ </p></div>
1789
+ </div>
1790
+
1791
+ <div>
1792
+ <h3><a href="#"> <?php echo LM_CRON_FTP_DETAILS?></a></h3>
1793
+ <div><p>
1794
+ <table class='adminform'>
1795
+
1796
+ <tr>
1797
+ <td width='250'>
1798
+ <?php echo LM_CRON_FTP_SERVER?>
1799
+ </td>
1800
+ <td>
1801
+ <input type=text size=50 name='cron_ftp_server' value='<?php echo $_CONFIG[cron_ftp_server]?>'>
1802
+ </td>
1803
+ </tr>
1804
+ <tr>
1805
+ <td>
1806
+ <?php echo LM_CRON_FTP_USER?>
1807
+ </td>
1808
+ <td>
1809
+ <input type=text size=50 name='cron_ftp_user' value='<?php echo $_CONFIG[cron_ftp_user]?>'>
1810
+ </td>
1811
+ </tr>
1812
+ <tr>
1813
+ <td>
1814
+ <?php echo LM_CRON_FTP_PASS?>
1815
+ </td>
1816
+ <td>
1817
+ <input type=text size=50 name='cron_ftp_pass' value='<?php echo $_CONFIG[cron_ftp_pass]?>'>
1818
+ </td>
1819
+ </tr>
1820
+ <tr>
1821
+ <td>
1822
+ <?php echo LM_CRON_FTP_PATH?>
1823
+ </td>
1824
+ <td>
1825
+ <input type=text size=50 name='cron_ftp_path' value='<?php echo $_CONFIG[cron_ftp_path]?>'>
1826
+ </td>
1827
+ </tr>
1828
+ <tr>
1829
+ <td>
1830
+ <!--<?php echo LM_CRON_FTP_DELB?>-->
1831
+ </td>
1832
+ <td>
1833
+ <input id="cron_ftp_delb" type=checkbox name='cron_ftp_delb' <?php if($_CONFIG[cron_ftp_delb]==1) echo "checked";?> value='1'>
1834
+ <label for="cron_ftp_delb"><?php echo LM_CRON_FTP_DELB?></label>
1835
+ </td>
1836
+ </tr>
1837
+ </table>
1838
+ </p></div>
1839
+ </div>
1840
+
1841
+ <div>
1842
+ <h3><a href="#"> <?php echo LM_AMAZON_S3?></a></h3>
1843
+ <div><p>
1844
+ <table class='adminform'>
1845
+
1846
+ <tr>
1847
+ <td width='250'>
1848
+ <?php #echo LM_AMAZON_S3_ACTIVATE?>
1849
+ </td>
1850
+ <td>
1851
+ <label for="cron_amazon_active"><?php echo LM_AMAZON_S3_ACTIVATE?></label>
1852
+ <input id="cron_amazon_active" type=checkbox name='cron_amazon_active' <?php if($_CONFIG[cron_amazon_active]==1) echo "checked";?> value='1'>
1853
+
1854
+ <label for="cron_amazon_ssl"><?php echo LM_AMAZON_S3_SSL?></label>
1855
+ <input id="cron_amazon_ssl" type=checkbox name='cron_amazon_ssl' <?php if($_CONFIG[cron_amazon_ssl]==1) echo "checked";?> value='1'>
1856
+ </td>
1857
+ </tr>
1858
 
1859
+ <tr>
1860
+ <td>
1861
+ <?php echo LM_AMAZON_S3_AWSACCESSKEY;?>
1862
+ </td>
1863
+ <td>
1864
+ <input type=text size=50 name='cron_amazon_awsAccessKey' value="<?php echo $_CONFIG['cron_amazon_awsAccessKey'];?>">
1865
+ </td>
1866
+ </tr>
1867
 
1868
+ <tr>
1869
+ <td>
1870
+ <?php echo LM_AMAZON_S3_AWSSECRETKEY;?>
1871
+ </td>
1872
+ <td>
1873
+ <input type=text size=50 name='cron_amazon_awsSecretKey' value="<?php echo $_CONFIG['cron_amazon_awsSecretKey'];?>">
1874
+ </td>
1875
+ </tr>
1876
+
1877
+ <tr>
1878
+ <td width='200'>
1879
+ <?php echo LM_AMAZON_S3_BUCKET;?>
1880
+ </td>
1881
+ <td>
1882
+ <input type=text size=50 name='cron_amazon_bucket' value="<?php echo $_CONFIG['cron_amazon_bucket'];?>">
1883
+ </td>
1884
+ </tr>
1885
 
1886
+ <tr>
1887
+ <td>
1888
+ <?php echo LM_AMAZON_S3_DIRNAME;?>
1889
+ </td>
1890
+ <td>
1891
+ <input type=text size=50 name='cron_amazon_dirname' value="<?php echo $_CONFIG['cron_amazon_dirname'];?>">
1892
+ </td>
1893
+ </tr>
1894
+ </tr>
1895
+ </table>
1896
+ </p></div>
1897
+ </div>
1898
+
1899
+ <div>
1900
+ <h3><a href="#"> <?php echo LM_DROPBOX?></a></h3>
1901
+ <div><p>
1902
+ <table class='adminform'>
1903
+
1904
+ <tr>
1905
+ <td width='250'>
1906
+ <?php #echo LM_AMAZON_S3_ACTIVATE?>
1907
+ </td>
1908
+ <td>
1909
+ <label for="cron_dropbox_active"><?php echo LM_DROPBOX_ACTIVATE?></label>
1910
+ <input id="cron_dropbox_active" type=checkbox name='cron_dropbox_active' <?php if($_CONFIG[cron_dropbox_active]==1) echo "checked";?> value='1'>
1911
+
1912
+
1913
+ </td>
1914
+ </tr>
1915
 
1916
+ <tr>
1917
+ <td>
1918
+ <?php echo LM_DROPBOX_AWSACCESSKEY;?>
1919
+ </td>
1920
+ <td>
1921
+ <input type=text size=50 name='cron_dropbox_Key' value="<?php echo $_CONFIG['cron_dropbox_Key'];?>">
1922
+ </td>
1923
+ </tr>
 
 
1924
 
1925
+ <tr>
1926
+ <td>
1927
+ <?php echo LM_DROPBOX_AWSSECRETKEY;?>
1928
+ </td>
1929
+ <td>
1930
+ <input type=text size=50 name='cron_dropbox_Secret' value="<?php echo $_CONFIG['cron_dropbox_Secret'];?>">
1931
+ </td>
1932
+ </tr>
1933
+
1934
+ <tr>
1935
+ <td>
1936
+ <?php echo LM_DROPBOX_DIRNAME;?>
1937
+ </td>
1938
+ <td>
1939
+ <input type=text size=50 name='cron_dropbox_dirname' value="<?php echo $_CONFIG['cron_dropbox_dirname'];?>">
1940
+ </td>
1941
+ </tr>
1942
+ </tr>
1943
+
1944
+ </tr>
1945
+ </table>
1946
+ </p></div>
1947
+ </div>
1948
+
1949
+ <div>
1950
+ <h3><a href="#"> <?php echo LM_CRON_EMAIL_DETAILS?></a></h3>
1951
+ <div><p>
1952
+ <table class='adminform'>
1953
+
1954
+ <tr>
1955
+ <td width="250">
1956
+ <?php echo LM_CRON_EMAIL_ACCOUNT?>
1957
+ </td>
1958
+ <td>
1959
+ <input type=text size=50 name='cron_email_address' value='<?php echo $_CONFIG[cron_email_address]?>'>
1960
+ </td>
1961
+ </tr>
1962
+ </table>
1963
+ </p></div>
1964
+ </div>
1965
+
1966
+ <div>
1967
+ <h3><a href="#"> <?php echo LM_CRON_MYSQL_DETAILS?></a></h3>
1968
+ <div><p>
1969
+ <table class='adminform'>
1970
+
1971
+ <tr bgcolor='#ffffff'>
1972
+ <td width='250'>
1973
+ <?php #echo LM_CRON_MYSQL_DROP?>
1974
+ </td>
1975
+ <td>
1976
+ <label for="cron_sql_drop"><?php echo LM_CRON_MYSQL_DROP?></label>
1977
+ <input id="cron_sql_drop" type=checkbox name='cron_sql_drop' value='1' <?php if($_CONFIG[cron_sql_drop]) echo "checked";?> >
1978
+ </td>
1979
+ </tr>
1980
+
1981
+ <?php
1982
+ if((abs($_CONFIG[system_mdatabases])==0) && ($_CONFIG[enable_db_backup]==1)){
1983
+ ?>
1984
+ <tr><td valign='top'>
1985
+ <?php echo LM_DATABASE_INCLUDE_DATABASES?>
1986
+ </td><td>
1987
+ <select name='databases_incl[]' MULTIPLE SIZE=5>
1988
+ <?php
1989
+
1990
+ $curent_dbs = explode(",", $_CONFIG['databases_incl_list']);
1991
+
1992
+ $query = @mysql_query("SHOW databases");
1993
+ while($row = @mysql_fetch_array($query)){
1994
+
1995
+ $table = $row[0];
1996
+
1997
+ if($table != $_CONFIG['mysql_database'])
1998
+
1999
+ if(in_array($table, $curent_dbs)){
2000
+
2001
+ echo "<option value='".$table."' selected>$table</option>";
2002
+
2003
+ }else{
2004
+
2005
+ echo "<option value='".$table."'>$table</option>";
2006
 
2007
+ }
2008
+ }
2009
+ ?>
2010
+ </select><br />
2011
+ <?php echo LM_DATABASE_INCLUDE_DATABASES_SUB?>
2012
+ </td></tr>
2013
+ <?php
2014
+ }
2015
+ ?>
2016
+ </table>
2017
+ </p></div>
2018
+ </div>
2019
+
2020
+ <div>
2021
+ <h3><a href="#"> <?php echo LM_CRON_DELETE_FILES?></a></h3>
2022
+ <div><p>
2023
+
2024
+ <script>
2025
+ $(function() {
2026
+ $( "#slider2" ).slider({
2027
+ value:parseInt(<?php echo (int)$_CONFIG[cron_file_delete];?>),
2028
+ min: 0,
2029
+ max: 100,
2030
+ step: 1,
2031
+ slide: function( event, ui ) {
2032
+ $( "#cron_file_delete" ).val( ui.value );
2033
+ }
2034
+ });
2035
+ $( "#cron_file_delete" ).val( $( "#slider2" ).slider( "value" ) );
2036
+ });
2037
+ </script>
2038
+
2039
+ <table class='adminform'>
2040
+
2041
+ <tr>
2042
+ <td width='250'>
2043
+ <?php #echo LM_CRON_DELETE_FILES_SUB_ACTIVE?>
2044
+ </td>
2045
+ <td>
2046
+ <label for="cron_file_delete_act"><?php echo LM_CRON_DELETE_FILES_SUB_ACTIVE?></label>
2047
+ <input id="cron_file_delete_act" type=checkbox name='cron_file_delete_act' <?php if ($_CONFIG['cron_file_delete_act'] == 1) echo 'checked';?> value='1'>
2048
+ </td>
2049
+ </tr>
2050
+ <tr>
2051
+ <td>
2052
+ <?php echo LM_CRON_DELETE_FILES_SUB?>
2053
+ </td>
2054
+ <td>
2055
+ <div id="slider2" style="width:300px;padding-top:5px;"></div>
2056
+ <br /><label for="cron_file_delete"></label>
2057
+ <input id="cron_file_delete" size=5 name='cron_file_delete' value='<?php echo $_CONFIG[cron_file_delete]?>'> days:
2058
+ </td>
2059
+ </tr>
2060
+ </table>
2061
+
2062
+ <table class='adminform'>
2063
+ <tr>
2064
+ <th colspan='2'>
2065
+ <?php echo LM_CRON_EXCLUDE?>
2066
+ </th>
2067
+ </tr>
2068
+ </tr>
2069
+ <tr>
2070
+ <td width='250'>
2071
+ <?php echo LM_CRON_EXCLUDE_DIR?>
2072
+ </td>
2073
+ <td>
2074
+ <textarea cols=50 rows=5 name='cron_exclude'><?php echo $_CONFIG[cron_exclude]?></textarea>
2075
+ </td>
2076
+ </tr>
2077
+
2078
+ </table>
2079
+ </p></div>
2080
+ </div>
2081
+
2082
+ </div>
2083
+ <?php
2084
+ $tabs->endTab();
2085
+ $tabs->startTab(LM_TAB_INFO,"6");
2086
+ ?>
2087
 
2088
+ <div id="configtabinside">
2089
+ <div>
2090
+ <h3><a href="#"><?php echo LM_CONFIG_INFO_PHP?></a></h3>
2091
+ <div><p>
2092
+
2093
+ <table class='adminform'>
2094
+
2095
+ <tr>
2096
+ <td width='250'>
2097
+ <?php echo LM_CONFIG_INFO_T_VERSION?>
2098
+ </td>
2099
+ <td>
2100
+ <b><?php
2101
+ $version = phpversion();
2102
+ $ver = str_replace(".", "", $version);
2103
+ $val = (version_compare(PHP_VERSION, '5.2.3') < 0)? $version: "Off";
2104
+ echo HTML_cloner::get_color($version, $val);
2105
+ ?></b>
2106
+ <br />
2107
+ <?php echo LM_CONFIG_INFO_VERSION?>
2108
+ </td>
2109
+ </tr>
2110
+
2111
+ <tr>
2112
+ <td>
2113
+ <?php echo LM_CONFIG_INFO_T_SAFEMODE?>
2114
+ </td>
2115
+ <td>
2116
+ <b><?php $val = (ini_get('safe_mode') != "")? ini_get('safe_mode'):"Off";
2117
+ echo HTML_cloner::get_color($val, 'On');
2118
+ ?></b>
2119
+ <br />
2120
+ <?php echo LM_CONFIG_INFO_SAFEMODE?>
2121
+ </td>
2122
+ </tr>
2123
+
2124
+ <tr>
2125
+ <td>
2126
+ <?php echo LM_CONFIG_INFO_T_MTIME?>
2127
+ </td>
2128
+ <td>
2129
+ <b><?php echo (ini_get('max_execution_time') != "")? ini_get('max_execution_time'):"no value";
2130
+
2131
+ ?></b>
2132
+ <br />
2133
+ <?php echo LM_CONFIG_INFO_TIME?>
2134
+ </td>
2135
+ </tr>
2136
+
2137
+ <tr>
2138
+ <td>
2139
+ <?php echo LM_CONFIG_INFO_T_MEML?>
2140
+ </td>
2141
+ <td>
2142
+ <b><?php echo (ini_get('memory_limit') != "")? ini_get('memory_limit'):"no value";?> </b>
2143
+ <br />
2144
+ <?php echo LM_CONFIG_INFO_MEMORY?>
2145
+ </td>
2146
+ </tr>
2147
+
2148
+ <tr>
2149
+ <td>
2150
+ <?php echo LM_CONFIG_INFO_T_BDIR?>
2151
+ </td>
2152
+ <td>
2153
+ <b><?php $val = (ini_get('open_basedir') != "")? ini_get('open_basedir'):"no value";
2154
+ echo HTML_cloner::get_color($val, '/');
2155
+ ?> </b>
2156
+ <br />
2157
+ <?php echo LM_CONFIG_INFO_BASEDIR?>
2158
+ </td>
2159
+ </tr>
2160
+
2161
+ <tr>
2162
+ <td>
2163
+ <?php echo LM_CONFIG_INFO_T_EXEC?>
2164
+ </td>
2165
+ <td>
2166
+ <b><?php
2167
+
2168
+ $out = "";
2169
+ if(function_exists("exec")){
2170
+
2171
+ $out = @exec("ls -al");
2172
+ }
2173
 
2174
+ $val = ($out != "")? "ENABLED":"<font color='red'>DISABLED</font>";
2175
+ echo HTML_cloner::get_color($val, 'DISABLED');
2176
+ ?> </b>
2177
+ <br />
2178
+ <?php echo LM_CONFIG_INFO_EXEC?>
2179
+ </td>
2180
+ </tr>
2181
+ </table>
2182
+ </p></div>
2183
+ </div>
2184
+ <div>
2185
+ <h3><a href="#"><?php echo LM_CONFIG_INFO_PATHS?></a></h3>
2186
+ <div><p>
2187
+ <table class='adminform'>
2188
+
2189
+ <tr>
2190
+ <td width='250'>
2191
+ <?php echo LM_CONFIG_INFO_ROOT_BPATH_TMP?>
2192
+ </td>
2193
+ <td>
2194
+ <b><?php $tmp_dir = realpath($_CONFIG['backup_path']."/administrator/backups");
2195
+ echo (@is_writeable( $tmp_dir ))? $tmp_dir . " is <font color=green>writeable</font>":$tmp_dir. " <font color=red>incorrect or unreadable</font>";?></b>
2196
+ <br />
2197
+ <?php echo LM_CONFIG_INFO_ROOT_PATH_TMP_SUB?>
2198
+ </td>
2199
+ </tr>
2200
+
2201
+ <tr>
2202
+ <td>
2203
+ <?php echo LM_CONFIG_INFO_ROOT_BPATH?>
2204
+ </td>
2205
+ <td>
2206
+ <b><?php echo (@is_readable($_CONFIG['backup_path']) )? $_CONFIG['backup_path'] . " is <font color=green>readable</font>":$_CONFIG['backup_path']. " <font color=red>incorrect or unreadable</font>";?></b>
2207
+ <br />
2208
+ <?php echo LM_CONFIG_INFO_ROOT_PATH_SUB?>
2209
+ </td>
2210
+ </tr>
2211
+
2212
+
2213
+ <tr>
2214
+ <td>
2215
+ <?php echo LM_CONFIG_INFO_T_BPATH?>
2216
+ </td>
2217
+ <td>
2218
+ <b><?php echo (@is_writeable($_CONFIG['clonerPath']) )? $_CONFIG['clonerPath'] . " is <font color=green>writeable</font>":$_CONFIG['clonerPath']. " <font color=red>unwriteable</font>";?></b>
2219
+ <br />
2220
+ <?php echo LM_CONFIG_INFO_BPATH?>
2221
+ </td>
2222
+ </tr>
2223
+
2224
+
2225
+ <tr>
2226
+ <td>
2227
+ <?php echo LM_CONFIG_INFO_T_TAR?>
2228
+ </td>
2229
+ <td>
2230
+ <b><?php
2231
+ if(function_exists('exec')){
2232
+ $info_tar_path = explode(" ", @exec("whereis tar"));
2233
+ }
2234
+ echo ($info_tar_path['1'] != "")? $info_tar_path['1']:"unable to determine";
2235
+ ?> </b>
2236
+ <br />
2237
+ <?php echo LM_CONFIG_INFO_TAR?>
2238
+ </td>
2239
+ </tr>
2240
+
2241
+
2242
+ <tr>
2243
+ <td>
2244
+ <?php echo LM_CONFIG_INFO_T_MSQL?>
2245
+ </td>
2246
+ <td>
2247
+ <b><?php
2248
+ if(function_exists('exec')){
2249
+ $info_msql_path = explode(" ", @exec("whereis mysqldump"));
2250
+ }
2251
+ echo ($info_msql_path['1'] != "")? $info_msql_path['1']:"unable to determine";
2252
+ ?> </b>
2253
+ <br />
2254
+ <?php echo LM_CONFIG_INFO_MSQL?>
2255
+ </td>
2256
+ </tr>
2257
 
2258
+ </table>
2259
+ </p></div>
 
 
 
 
 
 
 
2260
 
2261
+ </div></div>
 
 
 
 
2262
 
2263
+ <?php
2264
+ $tabs->endTab();
2265
+ $tabs->endPane();
2266
+ ?>
2267
+ <input type="hidden" name="option" value="com_cloner" />
2268
+ <input type="hidden" name="task" value="config" />
2269
+ <input type="hidden" name='action' value='save'>
2270
+ </form>
2271
 
2272
+ <?php
2273
+ }
2274
 
2275
+ function get_color($val, $comp){
 
 
 
2276
 
2277
+ if(!stristr($val, $comp))
2278
+ echo "<span style='color:green'>$val</span>";
2279
+ else
2280
+ echo "<span style='color:red'>$val</span>";
2281
 
2282
+ }
2283
 
2284
+ function TransferForm($option, $files){
2285
+ global $baDownloadPath, $mosConfig_absolute_path, $clonerPath, $task;
2286
 
2287
+ ?>
2288
+ <form action="index2.php" method="GET" name="adminForm">
2289
+ <script language="javascript" type="text/javascript">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2290
 
2291
 
2292
  function submitbutton(pressbutton) {
2388
  <form action="index2.php" method="post" name="adminForm">
2389
  <?php
2390
  $tabs = new mosTabs(1);
2391
+ ?>
2392
+
2393
+ <script>
2394
+ $(function() {
2395
+ $( "#tabs" ).tabs().find( ".ui-tabs-nav" ).sortable({ axis: "x" });
2396
+ $( "#radio_dbbackup" ).buttonset();
2397
+ $( "#radio_dbbackup1" ).button( { icons: {primary:'ui-icon-bullet'} } );
2398
+ $( "#radio_dbbackup2" ).button( { icons: {primary:'ui-icon-bullet'} } );
2399
+ });
2400
+ </script>
2401
+
2402
+
2403
+ <ul>
2404
+ <?php
2405
+ if($_CONFIG['enable_db_backup']){
2406
+ ?>
2407
+ <li><a href="#tabs-users-databse-options-tab"><?php echo LM_TAB_G_DATABASE;?></a></li>
2408
+ <?php }?>
2409
+ <li><a href="#tabs-users-files-options-tab"><?php echo LM_TAB_G_FILES;?></a></li>
2410
+ <li><a href="#tabs-users-comments-options-tab"><?php echo LM_TAB_G_COMMENTS;?></a></li>
2411
+ </ul>
2412
+
2413
+ <?php
2414
+ #$tabs->startPane("BGeneratePane");
2415
  if($_CONFIG['enable_db_backup']){
2416
  $tabs->startTab(LM_TAB_G_DATABASE,"users-databse-options-tab");
2417
  ?>
2418
 
2419
+ <div id="radio_dbbackup">
2420
  <table class="adminform">
2421
+ <!--<tr>
2422
  <th colspan=2>
2423
+ <b><?php #echo LM_DATABASE_ARCHIVE; ?></b>
2424
  </th>
2425
+ </tr>-->
 
 
 
2426
  <tr>
2427
+ <td>
2428
+ <label for="radio_dbbackup1"><?php echo LM_CONFIRM_DATABASE; ?></label>
2429
+ <input id="radio_dbbackup1" type="checkbox" id="dbbackup" name="dbbackup" checked value="1" />
2430
+ &nbsp;<label for="radio_dbbackup2">Add DROP SYNTAX</label>
2431
+ <input id="radio_dbbackup2" type="checkbox" id="dbbackup_drop" name="dbbackup_drop" value="1" />
2432
+ </td>
2433
  </tr>
2434
  <tr>
2435
  <td><?php echo "Mysql Compatibility"; ?> &nbsp;
2444
  <?php echo LM_DATABASE_EXCLUDE_TABLES?>
2445
  </th></tr>
2446
  <tr><td>
2447
+ <?php echo LM_DATABASE_CURRENT?> <b><?php echo $_CONFIG['mysql_database'];?></b><br />
2448
  <select name='excltables[]' MULTIPLE SIZE=15>
2449
  <?php
2450
 
2473
 
2474
  while($row = mysql_fetch_array($query)){
2475
 
2476
+ if($_CONFIG['mysql_database'] != $row[0])
2477
+ echo "<option value='".$row[0]."'>$row[0]</option>";
2478
 
2479
  }
2480
 
2488
  ?>
2489
 
2490
  </table>
2491
+ </div>
2492
  <?php
2493
  $tabs->endTab();
2494
  }
2502
  </tr>
2503
  <tr>
2504
  <td>
2505
+ <input type=text name='bname' value='' size=100><br/>
2506
  <?php echo LM_BACKUP_NAME_SUB?>
2507
  </td>
2508
  </tr>
2536
  ?>
2537
 
2538
  </table>
2539
+ <?php
2540
+ $tabs->endTab();
2541
+ $tabs->startTab(LM_TAB_G_COMMENTS,"users-comments-options-tab");
2542
+ ?>
2543
+ <div class="mainText">
2544
+ <h2><?php echo LM_TAB_G_COMMENTS_H2?></h2>
2545
+ <textarea name="backupComments" rows=20 cols=80></textarea>
2546
+ <br /><small> <?php echo LM_TAB_G_COMMENTS_NOTE?></small>
2547
+ </div>
2548
  <?php
2549
  $tabs->endTab();
2550
  $tabs->endPane();
2625
 
2626
  function showHelp( $option ) {
2627
  ?>
2628
+ <script>
2629
+ $(function() {
2630
+ $( "#tabs" ).tabs();
2631
+ });
2632
+ </script>
2633
+
2634
+ <div id="tabs" >
2635
+ <ul>
2636
+ <li><a href="#tabs-1"><?php echo LM_CREDIT_TOP?></a></li>
2637
+ </ul>
2638
+ <div id="tabs-1" >
2639
+ <div class="mainText">
2640
+
2641
+ <?php echo LM_CLONER_ABOUT?>
2642
+ </div>
2643
+ </div>
2644
+ </div>
2645
  <form action="index2.php" name="adminForm" method="post">
2646
  <input type="hidden" name="option" value="<?php echo $option; ?>"/>
2647
  <input type="hidden" name="task" value=""/>
2656
 
2657
  ?>
2658
 
2659
+ <script>
2660
+ $(function() {
2661
+ $( "#tabs" ).tabs();
2662
+ });
2663
+ </script>
2664
+
2665
+ <div id="tabs">
2666
+ <ul>
2667
+ <li><a href="#tabs-1"><?php echo LM_RESTORE_TOP?></a></li>
2668
+ </ul>
2669
+ <div id="tabs-1"><p class="mainText">
2670
+ <table border="0" align="center" cellspacing="0" cellpadding="2" width="100%" class="adminform">
2671
+ <tr>
2672
+ <td>
2673
+ <?php echo LM_CLONER_RESTORE?>
2674
+ </td>
2675
+ </tr>
2676
+ </table>
2677
+ </p></div>
2678
+ </div>
2679
  <form action="index2.php" name="adminForm" method="post">
2680
  <input type="hidden" name="option" value="<?php echo $option; ?>"/>
2681
  <input type="hidden" name="task" value=""/>
2688
  // ----------------------------------------------------------
2689
 
2690
  ?>
2691
+ <script>
2692
+ $(function() {
2693
+ $( "#tabs" ).tabs();
2694
+ });
2695
+ </script>
2696
+
2697
+ <div id="tabs">
2698
+ <ul>
2699
+ <li><a href="#tabs-1"><?php echo LM_CREDIT_TOP?></a></li>
2700
+ </ul>
2701
+ <div id="tabs-1"><p class="mainText">
2702
+ <table border="0" align="center" cellspacing="0" cellpadding="2" width="100%" class="adminform">
2703
+ <tr>
2704
+ <td>
2705
+ <?echo LM_CLONER_CREDITS?>
2706
+ </td>
2707
+ </tr>
2708
+ </table>
2709
+ </p></div>
2710
+ </div>
2711
  <form action="index2.php" name="adminForm" method="post">
2712
  <input type="hidden" name="option" value="<?php echo $option; ?>"/>
2713
  <input type="hidden" name="task" value=""/>
admin.cloner.php CHANGED
@@ -1,202 +1,226 @@
1
  <?php
2
- /*
3
- * admin.cloner.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
9
- * the Free Software Foundation; either version 2 of the License, or
10
- * (at your option) any later version.
11
- *
12
- * This program is distributed in the hope that it will be useful,
13
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
- * GNU General Public License for more details.
16
- *
17
- * You should have received a copy of the GNU General Public License
18
- * along with this program; if not, write to the Free Software
19
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
- * MA 02110-1301, USA.
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
-
39
- //Doing some basic authentification
40
- if ((!isset($_SESSION['clone'])) && ($task != 'dologin')) {
41
- $task = 'login';
42
-
43
- HTML_cloner::header();
44
-
45
- HTML_cloner::Login();
46
-
47
- HTML_cloner::footer();
48
-
49
- exit;
50
- } elseif ($task == 'dologin') {
51
- if (($_REQUEST['username'] == $_CONFIG['jcuser']) && (md5($_REQUEST['password']) == $_CONFIG['jcpass'])) {
52
- if (function_exists('session_register')) {
53
- @session_register('clone');
54
- }
55
- $_SESSION['clone'] = 1;
56
-
57
- mosRedirect('index2.php?option=' . $option, "Welcome to XCloner backend");
58
- } else {
59
-
60
-
61
- mosRedirect('index2.php?option=' . $option, "Incorrect username and/or password");
62
- }
63
- }
64
-
65
-
66
-
67
- //###########GLOBALS in effect
68
- $GLOBALS['lang_dir'] = $lang_dir;
69
- //###########
70
- $lang_array = get_avalaible_langs();
71
-
72
-
73
- // retrieve row selection from forms
74
- $cid = $_REQUEST['cid'];
75
- if (!is_array($cid)) {
76
- $cid = array(0);
77
- }
 
78
 
79
  if(!$_REQUEST['nohtml'])
80
- if (($task != 'download') and (($_REQUEST['task']!="refresh") or (!$_CONFIG['refresh_mode'])))
81
- HTML_cloner::header();
82
-
83
-
84
- //########## SETTING THE GLOBALS VARIABLES #########################
85
-
86
- $GLOBALS['joomla_compatible'] = $joomla_compatible;
87
-
88
- $GLOBALS['_CONFIG'] = $_CONFIG;
89
-
90
- $GLOBALS['clonerPath'] = $clonerPath;
91
-
92
- $GLOBALS['baDownloadPath'] = $baDownloadPath;
93
-
94
- $GLOBALS['config_file'] = $config_file;
95
-
96
- $GLOBALS['lang_array'] = $lang_array;
97
-
98
- openXLog();
99
-
100
- // process the workflow selection
101
- switch ($task) {
102
- case 'rename_save':
103
- case 'rename':
104
- clone_rename($option);
105
- break;
106
- case 'action':
107
- action($option);
108
- break;
109
-
110
-
111
- case 'cancel_lang':
112
- mosRedirect('index2.php?option=' . $option . "&task=lang");
113
- break;
114
- case 'add_lang':
115
- case 'add_lang_new':
116
- translator_add($option, $task);
117
- break;
118
- case 'save_lang_apply':
119
- case 'save_lang':
120
- case 'edit_lang':
121
- translator_edit($option, $task);
122
- break;
123
-
124
-
125
- case 'del_lang':
126
- case 'lang':
127
- translator($option);
128
- break;
129
-
130
- case 'recurse_files':
131
- goRecurseFiles();
132
- break;
133
-
134
- case 'refresh':
135
- generateBackuprefresh($cid, $option, $_REQUEST['backup'], $_CONFIG['refresh_mode']);
136
- break;
137
-
138
- case 'generate':
139
- generateBackup($cid, $option);
140
- break;
141
-
142
- case 'confirm':
143
- deleteXLog();
144
- confirmBackup($option);
145
- break;
146
- case 'download':
147
- downloadBackup($_REQUEST[file]);
148
- break;
149
- case 'cron':
150
- HTML_cloner::Cron();
151
- break;
152
- case 'about':
153
- case 'credits':
154
- showHelp($option);
155
- break;
156
- case 'restore':
157
- HTML_cloner::Restore($option);
158
- break;
159
-
160
- case 'cron_delete':
161
- if (unlink($_CONFIG['multiple_config_dir'] . "/" . $_REQUEST['fconfig']))
162
- $msg = " was deleted";
163
- else
164
- $msg = " was not deleted, please delete it manually!";
165
-
166
- mosRedirect('index2.php?option=' . $option . "&task=config", $_REQUEST['fconfig'] . $msg);
167
- break;
168
-
169
- case 'remove':
170
- deleteBackups($cid, $option);
171
- break;
172
- case 'continue':
173
- case 'move':
174
- case 'clone':
175
- moveBackup($option);
176
- break;
177
-
178
- case 'cancel':
179
- mosRedirect('index2.php?option=' . $option);
180
- break;
181
- case 'config':
182
- config($option);
183
- break;
184
- case 'rename_cancel':
185
- mosRedirect('index2.php?option=' . $option . "&task=view");
186
- break;
187
- case 'show':
188
- case 'view':
189
- showBackups($option);
190
- break;
191
- case 'logout':
192
- doLogout();
193
- break;
194
- default:
195
- fdefault();
196
- break;
197
- }
198
-
199
- closeXLog();
200
-
201
- HTML_cloner::footer();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  ?>
1
  <?php
2
+ /*
3
+ * admin.cloner.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
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ * MA 02110-1301, USA.
21
+ */
22
+
23
+
24
+ session_start();
25
+ header('Content-Type: text/html; charset=utf-8');
26
+ @set_time_limit("3600");
27
+ @error_reporting(E_ALL ^ E_NOTICE);
28
+
29
+ define("_VALID_MOS", 1);
30
+
31
+ //load configuration
32
+ $config_file = "cloner.config.php";
33
+ require_once($config_file);
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
+ //Doing some basic authentification
42
+ if ((!isset($_SESSION['clone'])) && ($task != 'dologin')) {
43
+ $task = 'login';
44
+
45
+ $html = new HTML_cloner();
46
+ $html->header();
47
+
48
+ $html->Login();
49
+
50
+ $html->footer();
51
+
52
+ exit;
53
+ } elseif ($task == 'dologin') {
54
+ if (($_REQUEST['username'] == $_CONFIG['jcuser']) && (md5($_REQUEST['password']) == $_CONFIG['jcpass'])) {
55
+ if (function_exists('session_register')) {
56
+ @session_register('clone');
57
+ }
58
+ $_SESSION['clone'] = 1;
59
+
60
+ mosRedirect('index2.php?option=' . $option, "Welcome to XCloner backend");
61
+ } else {
62
+
63
+
64
+ mosRedirect('index2.php?option=' . $option, "Incorrect username and/or password");
65
+ }
66
+ }
67
+
68
+ //###########GLOBALS in effect
69
+ $GLOBALS['lang_dir'] = $lang_dir;
70
+ //###########
71
+ $lang_array = get_avalaible_langs();
72
+
73
+
74
+ // retrieve row selection from forms
75
+ $cid = $_REQUEST['cid'];
76
+ if (!is_array($cid)) {
77
+ $cid = array(0);
78
+ }
79
 
80
  if(!$_REQUEST['nohtml'])
81
+ if (($task != 'download') and (($_REQUEST['task']!="refresh") or (!$_CONFIG['refresh_mode']))){
82
+ //HTML_cloner::header();
83
+ $html = new HTML_cloner();
84
+ $html->header();
85
+ }
86
+
87
+ //########## SETTING THE GLOBALS VARIABLES #########################
88
+
89
+ $GLOBALS['joomla_compatible'] = $joomla_compatible;
90
+
91
+ $GLOBALS['_CONFIG'] = $_CONFIG;
92
+
93
+ $GLOBALS['clonerPath'] = $clonerPath;
94
+
95
+ $GLOBALS['baDownloadPath'] = $baDownloadPath;
96
+
97
+ $GLOBALS['config_file'] = $config_file;
98
+
99
+ $GLOBALS['lang_array'] = $lang_array;
100
+
101
+ openXLog();
102
+
103
+ // process the workflow selection
104
+ switch ($task) {
105
+ case 'rename_save':
106
+ case 'rename':
107
+ clone_rename($option);
108
+ break;
109
+ case 'action':
110
+ action($option);
111
+ break;
112
+
113
+
114
+ case 'cancel_lang':
115
+ mosRedirect('index2.php?option=' . $option . "&task=lang");
116
+ break;
117
+ case 'add_lang':
118
+ case 'add_lang_new':
119
+ translator_add($option, $task);
120
+ break;
121
+ case 'save_lang_apply':
122
+ case 'save_lang':
123
+ case 'edit_lang':
124
+ translator_edit($option, $task);
125
+ break;
126
+
127
+
128
+ case 'del_lang':
129
+ case 'lang':
130
+ translator($option);
131
+ break;
132
+
133
+ case 'recurse_database';
134
+ goRecurseDatabases();
135
+ break;
136
+
137
+ case 'recurse_files':
138
+ goRecurseFiles();
139
+ break;
140
+
141
+ case 'cleanup':
142
+ include_once("classes/main.class.php");
143
+ $main = new Main();
144
+ $main->init($_CONFIG);
145
+ $main->cleanUp();
146
+ break;
147
+
148
+ case 'refresh':
149
+ generateBackuprefresh($cid, $option, $_REQUEST['backup'], $_CONFIG['refresh_mode']);
150
+ break;
151
+
152
+ case 'generate':
153
+ if($_CONFIG['refresh_mode']){
154
+ $_REQUEST['mode'] = "start";
155
+ if($_CONFIG['enable_db_backup'])
156
+ goRecurseDatabases();
157
+ //initBackup($_REQUEST['bname']);
158
+ //break;
159
+ }
160
+ generateBackup($cid, $option);
161
+ break;
162
+
163
+ case 'confirm':
164
+ deleteXLog();
165
+ confirmBackup($option);
166
+ break;
167
+ case 'download':
168
+ downloadBackup($_REQUEST[file]);
169
+ break;
170
+ case 'cron':
171
+ $html->Cron();
172
+ break;
173
+ case 'about':
174
+ case 'credits':
175
+ showHelp($option);
176
+ break;
177
+ case 'restore':
178
+ $html->Restore($option);
179
+ break;
180
+
181
+ case 'cron_delete':
182
+ if (unlink($_CONFIG['multiple_config_dir'] . "/" . $_REQUEST['fconfig']))
183
+ $msg = " was deleted";
184
+ else
185
+ $msg = " was not deleted, please delete it manually!";
186
+
187
+ mosRedirect('index2.php?option=' . $option . "&task=config", $_REQUEST['fconfig'] . $msg);
188
+ break;
189
+
190
+ case 'delete':
191
+ case 'remove':
192
+ deleteBackups($cid, $option);
193
+ break;
194
+ case 'continue':
195
+ case 'move':
196
+ case 'clone':
197
+ moveBackup($option);
198
+ break;
199
+
200
+ case 'cancel':
201
+ mosRedirect('index2.php?option=' . $option);
202
+ break;
203
+ case 'config':
204
+ config($option);
205
+ break;
206
+ case 'rename_cancel':
207
+ mosRedirect('index2.php?option=' . $option . "&task=view");
208
+ break;
209
+ case 'show':
210
+ case 'view':
211
+ showBackups($option);
212
+ break;
213
+ case 'logout':
214
+ doLogout();
215
+ break;
216
+ default:
217
+ fdefault();
218
+ break;
219
+ }
220
+
221
+ closeXLog();
222
+ if(!$_REQUEST['nohtml'])
223
+ $html->footer();
224
+
225
+ @mysql_close($link);
226
  ?>
admin.xcloner-backupandrestore.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
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
+ ?>
browser/files_inpage.php CHANGED
@@ -1,18 +1,25 @@
1
  <?php
2
  @ini_set("error_reporting", "2");
3
 
 
 
4
  $thisApp=$_SERVER['PHP_SELF'] . "?browse=true";
5
 
 
 
 
 
 
 
6
  if(isset($_GET['browse'])){
7
  $dir = isset($_GET['dir']) ? $_GET['dir'] : '/files';
8
  if(strpos($dir, "../")===true){
9
  exit;
10
- }
11
-
12
  }else{
13
 
14
  echo "Please wait... we are loading the folder structure";
15
 
16
  }
17
 
18
- ?>
1
  <?php
2
  @ini_set("error_reporting", "2");
3
 
4
+ define("_VALID_MOS", 1);
5
+
6
  $thisApp=$_SERVER['PHP_SELF'] . "?browse=true";
7
 
8
+ $fp = @fopen($_CONFIG['exfile'], "w");
9
+ if($fp){
10
+ @fwrite($fp, $_CONFIG['cron_exclude']);
11
+ @fclose($fp);
12
+ }
13
+
14
  if(isset($_GET['browse'])){
15
  $dir = isset($_GET['dir']) ? $_GET['dir'] : '/files';
16
  if(strpos($dir, "../")===true){
17
  exit;
18
+ }
 
19
  }else{
20
 
21
  echo "Please wait... we are loading the folder structure";
22
 
23
  }
24
 
25
+ ?>
browser/files_xml.php CHANGED
@@ -10,9 +10,17 @@
10
  * Date: November 2010
11
  **/
12
 
 
 
 
 
 
 
 
 
13
  header("Cache-Control: no-cache");
14
  header("Pragma: nocache");
15
- header("Content-Type: text/xml");
16
 
17
  error_reporting(2);
18
 
@@ -22,7 +30,7 @@ if($_COOKIE["auth_clone"] != 1){
22
  exit;
23
  }
24
 
25
-
26
  include("../cloner.config.php");
27
  include("../common.php");
28
 
@@ -45,15 +53,15 @@ $path = $_REQUEST['path'];
45
  $loc = $_REQUEST['dir'];
46
 
47
  if(!is_dir($_CONFIG['backup_path'])){
48
-
49
  echo "<directory location=\"Error: Directory $_CONFIG[backup_path] does not exist!\"></directory>";
50
  exit;
51
-
52
  }elseif(!is_readable($_CONFIG['backup_path'])){
53
-
54
  echo "<directory location=\"Error: Directory $_CONFIG[backup_path] is not readable!\"></directory>";
55
  exit;
56
-
57
  }
58
 
59
 
@@ -70,8 +78,8 @@ elseif($_REQUEST['act'] == "uncheckall"){
70
 
71
  if($loc == "")
72
  $loc = "/";
73
-
74
-
75
  $data = "";
76
 
77
  if($fp = @fopen($exfile,"r")){
@@ -84,7 +92,6 @@ fclose($fp);
84
  $_COOKIES = explode("\r\n", $data);
85
 
86
 
87
-
88
  $exc = 0;
89
 
90
  if($fp = @fopen($exfile,"w")){
@@ -127,10 +134,10 @@ fclose($fp);
127
 
128
  }
129
  else{
130
-
131
  echo "<directory location=\"Error: Unable to write to file $exfile\"></directory>";
132
  exit;
133
-
134
  }
135
 
136
  $_COOKIES = explode("\r\n", $data);
@@ -187,7 +194,7 @@ sort($exclude);
187
  $check = 'checked';
188
  else
189
  $check = '';
190
-
191
  echo "<file check='$check' link=\"#\">".htmlspecialchars($file)."</file>";
192
 
193
  }
@@ -202,7 +209,7 @@ sort($exclude);
202
 
203
  function check($loc, $exfile, $act ){
204
  global $_CONFIG;
205
-
206
  $fulldir = $loc;
207
  $flist = array();
208
  $_COOKIES = array();
@@ -235,7 +242,7 @@ function check($loc, $exfile, $act ){
235
  if($act == 1){
236
 
237
  $flist = @array_merge($_COOKIES, $flist);
238
-
239
  }
240
  else{
241
 
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; charset=utf-8");
24
 
25
  error_reporting(2);
26
 
30
  exit;
31
  }
32
 
33
+
34
  include("../cloner.config.php");
35
  include("../common.php");
36
 
53
  $loc = $_REQUEST['dir'];
54
 
55
  if(!is_dir($_CONFIG['backup_path'])){
56
+
57
  echo "<directory location=\"Error: Directory $_CONFIG[backup_path] does not exist!\"></directory>";
58
  exit;
59
+
60
  }elseif(!is_readable($_CONFIG['backup_path'])){
61
+
62
  echo "<directory location=\"Error: Directory $_CONFIG[backup_path] is not readable!\"></directory>";
63
  exit;
64
+
65
  }
66
 
67
 
78
 
79
  if($loc == "")
80
  $loc = "/";
81
+
82
+
83
  $data = "";
84
 
85
  if($fp = @fopen($exfile,"r")){
92
  $_COOKIES = explode("\r\n", $data);
93
 
94
 
 
95
  $exc = 0;
96
 
97
  if($fp = @fopen($exfile,"w")){
134
 
135
  }
136
  else{
137
+
138
  echo "<directory location=\"Error: Unable to write to file $exfile\"></directory>";
139
  exit;
140
+
141
  }
142
 
143
  $_COOKIES = explode("\r\n", $data);
194
  $check = 'checked';
195
  else
196
  $check = '';
197
+
198
  echo "<file check='$check' link=\"#\">".htmlspecialchars($file)."</file>";
199
 
200
  }
209
 
210
  function check($loc, $exfile, $act ){
211
  global $_CONFIG;
212
+
213
  $fulldir = $loc;
214
  $flist = array();
215
  $_COOKIES = array();
242
  if($act == 1){
243
 
244
  $flist = @array_merge($_COOKIES, $flist);
245
+
246
  }
247
  else{
248
 
browser/xmlhttp.js CHANGED
@@ -35,7 +35,7 @@ function processXMLRequest() {
35
 
36
  function do_browser(){
37
  targetDiv=document.getElementById("browser");
38
-
39
  if(loadXMLDoc("browser/files_xml.php")){
40
  targetDiv.className="searching";
41
  targetDiv.innerHTML="";
@@ -102,7 +102,7 @@ function checkc(value){
102
  function useXML(xmlInfo){
103
  targetDiv.className="";
104
  message = "";
105
-
106
  var infoTags=xmlInfo.getElementsByTagName("directory");
107
  var loc=infoTags[0].getAttribute("location");
108
  if(loc == "")
@@ -124,11 +124,11 @@ function useXML(xmlInfo){
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"){
134
 
@@ -150,5 +150,5 @@ function useXML(xmlInfo){
150
  }
151
 
152
  //stringHTML = stringHTML+ "</form>";
153
- targetDiv.innerHTML= "<table align='right' width='200'><tr><td align='right'><b>" + "Excluded items list:" + "</b><br />"+ message+"</td></tr></table>" + stringHTML ;
154
  }
35
 
36
  function do_browser(){
37
  targetDiv=document.getElementById("browser");
38
+
39
  if(loadXMLDoc("browser/files_xml.php")){
40
  targetDiv.className="searching";
41
  targetDiv.innerHTML="";
102
  function useXML(xmlInfo){
103
  targetDiv.className="";
104
  message = "";
105
+
106
  var infoTags=xmlInfo.getElementsByTagName("directory");
107
  var loc=infoTags[0].getAttribute("location");
108
  if(loc == "")
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"){
134
 
150
  }
151
 
152
  //stringHTML = stringHTML+ "</form>";
153
+ targetDiv.innerHTML= "<table align='right' width='450'><tr><td align='right'><b>" + "Excluded items list:" + "</b><br />"+ message+"</td></tr></table>" + stringHTML ;
154
  }
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/S3.php CHANGED
@@ -28,6 +28,9 @@
28
  * Amazon S3 is a trademark of Amazon.com, Inc. or its affiliates.
29
  */
30
 
 
 
 
31
  /**
32
  * Amazon S3 PHP class
33
  *
@@ -794,7 +797,7 @@ class S3 {
794
  }
795
  array_push($policy->conditions, array('content-length-range', 0, $maxFileSize));
796
  $policy = base64_encode(str_replace('\/', '/', json_encode($policy)));
797
-
798
  // Create parameters
799
  $params = new stdClass;
800
  $params->AWSAccessKeyId = self::$__accessKey;
28
  * Amazon S3 is a trademark of Amazon.com, Inc. or its affiliates.
29
  */
30
 
31
+ /** ensure this file is being included by a parent file */
32
+ defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
33
+
34
  /**
35
  * Amazon S3 PHP class
36
  *
797
  }
798
  array_push($policy->conditions, array('content-length-range', 0, $maxFileSize));
799
  $policy = base64_encode(str_replace('\/', '/', json_encode($policy)));
800
+
801
  // Create parameters
802
  $params = new stdClass;
803
  $params->AWSAccessKeyId = self::$__accessKey;
administrator/backups/.excl → classes/error.class.php RENAMED
File without changes
classes/fileRecursion.php CHANGED
@@ -27,6 +27,7 @@ class fileRecursion{
27
 
28
  private static $fp;
29
  private static $fpd;
 
30
  private static $d_arr;
31
  private static $f_arr;
32
  private static $BACKUP_EXTENSIONS = array("tar", "zip", "tgz", "tar.gz");
@@ -39,17 +40,22 @@ class fileRecursion{
39
  public static $TEMP_EXCL = "tmp/.excl";
40
  public static $TEMP_DIR = "/opt/lampp/htdocs/joomla/administrator/backups"; //exclude other backups
41
  public static $START_DIR = "/"; # Backups Start Dir
 
 
42
 
43
 
44
 
45
- public static function setData($TEMP_PERM,$TEMP_EXCL,$TEMP_D_ARR,$TEMP_DIR, $START_DIR) {
46
 
47
- self::$TEMP_PERM = $TEMP_PERM;
48
- self::$TEMP_EXCL = $TEMP_EXCL;
49
- self::$TEMP_D_ARR = $TEMP_D_ARR;
50
- self::$TEMP_DIR = $TEMP_DIR;
51
- self::$START_DIR = $START_DIR;
 
 
52
  }
 
53
  /*
54
  * Init the recursion system
55
  * name: init
@@ -74,6 +80,7 @@ class fileRecursion{
74
 
75
  self::$fp = fopen(self::$TEMP_PERM, "a");
76
  self::$fpd = fopen(self::$TEMP_D_ARR, "w");
 
77
 
78
  self::initEXCL();
79
 
@@ -84,6 +91,20 @@ class fileRecursion{
84
 
85
  }
86
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  /*
88
  * Count the number of files saved in TEMP_PERM
89
  * name: countPermFiles
@@ -327,6 +348,23 @@ class fileRecursion{
327
 
328
  }
329
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
330
  /*
331
  * Writing file details(path, permissions, size) to file
332
  *
@@ -338,12 +376,23 @@ class fileRecursion{
338
  public static function writePermFile($file, $append = "", $force = 0){
339
 
340
  $file = realpath($file);
 
341
  if((self::isNotExcluded($file)) or ($force)){
 
342
  $fperm = substr(sprintf('%o', @fileperms($file)), -4);
343
  $fsize = self::getFileSize($file);
344
-
 
 
 
 
 
 
 
 
 
345
  $file = str_replace(self::$START_DIR, "", str_replace("\\","/", $file));
346
-
347
  fwrite(self::$fp, $file."|".$fperm."|".$fsize."|".$append."\n");
348
  self::debug($file ." added to list");
349
  }
27
 
28
  private static $fp;
29
  private static $fpd;
30
+ private static $fpe;
31
  private static $d_arr;
32
  private static $f_arr;
33
  private static $BACKUP_EXTENSIONS = array("tar", "zip", "tgz", "tar.gz");
40
  public static $TEMP_EXCL = "tmp/.excl";
41
  public static $TEMP_DIR = "/opt/lampp/htdocs/joomla/administrator/backups"; //exclude other backups
42
  public static $START_DIR = "/"; # Backups Start Dir
43
+ public static $EXCLUDE_FILES_SIZE = -1; //disabled
44
+ public static $TEMP_OVERSIZED_FILE = "tmp/.oversized_files";
45
 
46
 
47
 
48
+ public static function setData($data) {
49
 
50
+ self::$TEMP_PERM = $data['TEMP_PERM'];
51
+ self::$TEMP_EXCL = $data['TEMP_EXCL'];
52
+ self::$TEMP_D_ARR = $data['TEMP_D_ARR'];
53
+ self::$TEMP_DIR = $data['TEMP_DIR'];
54
+ self::$START_DIR = $data['START_DIR'];
55
+ self::$EXCLUDE_FILES_SIZE = $data['EXCLUDE_FILES_SIZE'];
56
+ self::$TEMP_OVERSIZED_FILE = $data['TEMP_OVERSIZED_FILE'];
57
  }
58
+
59
  /*
60
  * Init the recursion system
61
  * name: init
80
 
81
  self::$fp = fopen(self::$TEMP_PERM, "a");
82
  self::$fpd = fopen(self::$TEMP_D_ARR, "w");
83
+ self::$fpe = fopen(self::$TEMP_OVERSIZED_FILE, "a");
84
 
85
  self::initEXCL();
86
 
91
 
92
  }
93
 
94
+ /*
95
+ * We close the stuff left opened
96
+ * name: close
97
+ * @param
98
+ * @return
99
+ */
100
+ public static function close(){
101
+
102
+ @fclose(self::$fp );
103
+ @fclose(self::$fpd );
104
+ @fclose(self::$fpe );
105
+
106
+ }
107
+
108
  /*
109
  * Count the number of files saved in TEMP_PERM
110
  * name: countPermFiles
348
 
349
  }
350
 
351
+ public static function getOverLimitFiles(){
352
+ @fclose(self::$fpe);
353
+ $files = explode("\n", file_get_contents(self::$TEMP_OVERSIZED_FILE));
354
+
355
+ return array_diff($files, array(""));
356
+ }
357
+
358
+ public static function writeExcludedFile($file, $fsize = 0){
359
+
360
+ self::debug("Excluded $file from list as it is bigger than ". self::$EXCLUDE_FILES_SIZE." MB!!!");
361
+
362
+ if(self::$fpe){
363
+ fwrite(self::$fpe, $file."\t(".$fsize." bytes)\n");
364
+ }
365
+
366
+ }
367
+
368
  /*
369
  * Writing file details(path, permissions, size) to file
370
  *
376
  public static function writePermFile($file, $append = "", $force = 0){
377
 
378
  $file = realpath($file);
379
+
380
  if((self::isNotExcluded($file)) or ($force)){
381
+ // we check if file is not excluded
382
  $fperm = substr(sprintf('%o', @fileperms($file)), -4);
383
  $fsize = self::getFileSize($file);
384
+ $sizeLimit = (self::$EXCLUDE_FILES_SIZE)*1024*1024; // we limit by MB
385
+
386
+ if(intval(self::$EXCLUDE_FILES_SIZE) > -1){
387
+ if(($fsize > $sizeLimit) and is_file($file)){
388
+ //we check if file is larger than $EXCLUDE_FILES_SIZE
389
+ self::writeExcludedFile($file, $fsize);
390
+ return;
391
+ }
392
+ }
393
+
394
  $file = str_replace(self::$START_DIR, "", str_replace("\\","/", $file));
395
+
396
  fwrite(self::$fp, $file."|".$fperm."|".$fsize."|".$append."\n");
397
  self::debug($file ." added to list");
398
  }
classes/index.html CHANGED
File without changes
classes/main.class.php ADDED
@@ -0,0 +1,116 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * main.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
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ * MA 02110-1301, USA.
21
+ */
22
+
23
+ class Main{
24
+
25
+ public static $_CONFIG;
26
+
27
+
28
+ /*
29
+ *
30
+ * name: init
31
+ * @param
32
+ * @return
33
+ */
34
+ public static function init($_CONFIG){
35
+ self::$_CONFIG = $_CONFIG;
36
+ }
37
+
38
+ /*
39
+ *
40
+ * name: unknown
41
+ * @param
42
+ * @return
43
+ */
44
+ public static function initBackup($backupName){
45
+
46
+ self::generateBackupName($backupName);
47
+
48
+ }
49
+
50
+ /*
51
+ * Will cleanup the temporary directory
52
+ *
53
+ * name: cleanUp
54
+ * @param
55
+ * @return
56
+ */
57
+ public static function cleanUp(){
58
+
59
+ $dir = self::$_CONFIG['temp_dir'] ;
60
+
61
+ if (@is_dir($dir)) {
62
+ if ($dh = @opendir($dir)) {
63
+ while (($file = @readdir($dh)) !== false) {
64
+ if(($file!=".") and ($file!="..")){
65
+ if(($file[0] == ".") and ($file[0] != ".htaccess"))
66
+ //cleanup temp files
67
+ @unlink($dir."/".$file);
68
+ elseif(strstr( $file, "-sql.sql") != "")
69
+ //cleanup sql files
70
+ @unlink($dir."/".$file);
71
+
72
+ }
73
+ }
74
+ closedir($dh);
75
+ }
76
+ }
77
+
78
+ }
79
+
80
+ public static function generateBackupName($backupName, $backupDatabase = 0, $dbbackup_drop = 0){
81
+
82
+ $domainname = $_SERVER['HTTP_HOST'];
83
+
84
+ if ((self::$_CONFIG['mem']) && ($_CONFIG['backup_refresh'])) {
85
+ $f_ext = '.tar';
86
+ $_CONFIG['tarcompress'] = '';
87
+ } elseif (self::$_CONFIG['backup_compress']) {
88
+ $f_ext = '.tgz';
89
+ $_CONFIG['tarcompress'] = 'z';
90
+ } else {
91
+ $f_ext = '.tar';
92
+ $_CONFIG['tarcompress'] = '';
93
+ }
94
+
95
+
96
+ if ($backupName == "") {
97
+ if ($backupDatabase == 1) {
98
+ if ($_REQUEST['dbbackup_drop']) {
99
+ $filename = 'backup_' . date("Y-m-d_H-i") . '_' . $domainname . '-sql-drop' . $f_ext;
100
+ } else {
101
+ $filename = 'backup_' . date("Y-m-d_H-i") . '_' . $domainname . '-sql-nodrop' . $f_ext;
102
+ }
103
+ } else
104
+ $filename = 'backup_' . date("Y-m-d_H-i") . '_' . $domainname . '-nosql' . $f_ext;
105
+ } else {
106
+ $filename = $_REQUEST['bname'] . $f_ext;
107
+ }
108
+
109
+ return $filename;
110
+
111
+ }
112
+
113
+ }
114
+
115
+
116
+ ?>
classes/mysqlBackup.class.php ADDED
@@ -0,0 +1,488 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
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
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ * MA 02110-1301, USA.
21
+ */
22
+
23
+
24
+ class DB{
25
+
26
+ public static $dbHostname = "localhost";
27
+ public static $dbUsername = "root";
28
+ public static $dbPassword = "";
29
+ public static $dbDatabase = "";
30
+ public static $excludedTables = array();
31
+
32
+ public static $debug = 0;
33
+ public static $recordsPerSession = 10000;
34
+ public static $dbCompatibility = "";
35
+ public static $dbDropSyntax = 0;
36
+ public static $countRecords = 0;
37
+
38
+ private static $link;
39
+ private static $db_selected;
40
+
41
+ public static $TEMP_DBPROCESS_FILE = "tmp/.database";
42
+ public static $TEMP_DUMP_FILE = "tmp/database-sql.sql";
43
+
44
+ /*
45
+ *Return any error
46
+ *
47
+ * name: error
48
+ * @param string $message
49
+ * @return
50
+ */
51
+ public function error($message, $force = ""){
52
+
53
+ $return = "";
54
+ $date = date("M j, Y @ H:i:s");
55
+
56
+ if((self::$debug) && ($force)){
57
+ //we have debug message as force is 1
58
+ printf("Debug(%s) - %s \n", $date, $message);
59
+ }
60
+
61
+ if(!$force){
62
+ //we have an error message
63
+ printf("Error(%s) - %s \n", $date, $message);
64
+ }
65
+
66
+ return;
67
+
68
+ }
69
+
70
+ /*
71
+ * Initialize the database connection
72
+ *
73
+ * name: init
74
+ * @param array $data {'dbHostname', 'dbUsername', 'dbPassword', 'dbDatabase'}
75
+ * @return
76
+ */
77
+ public function init($data, $start = 0){
78
+
79
+ self::$dbHostname = $data['dbHostname'];
80
+ self::$dbUsername = $data['dbUsername'];
81
+ self::$dbPassword = $data['dbPassword'];
82
+ self::$dbDatabase = $data['dbDatabase'];
83
+ self::$excludedTables = $data['excludedTables'];
84
+ self::$TEMP_DBPROCESS_FILE = $data['TEMP_DBPROCESS_FILE'];
85
+ self::$TEMP_DUMP_FILE = $data['TEMP_DUMP_FILE'];
86
+ self::$recordsPerSession = $data['recordsPerSession'];
87
+ self::$dbCompatibility = $data['dbCompatibility'];
88
+ self::$dbDropSyntax = $data['dbDropSyntax'];
89
+
90
+ self::connect();
91
+ self::headers();
92
+
93
+ if($start){
94
+ @unlink(self::$TEMP_DBPROCESS_FILE);
95
+ }
96
+
97
+ }
98
+
99
+ /*
100
+ * Connect to the database
101
+ *
102
+ * name: connect
103
+ * @param
104
+ * @return
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
+ }
121
+
122
+ /*
123
+ * Disconnect from the database
124
+ *
125
+ * name: disconnect
126
+ * @param
127
+ * @return
128
+ */
129
+ public function disconnect(){
130
+
131
+ mysql_close(self::$link);
132
+
133
+ }
134
+
135
+ /*
136
+ * Send some special headers after the connection is initialized
137
+ *
138
+ * name: headers
139
+ * @param
140
+ * @return
141
+ */
142
+ private function headers(){
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
+
150
+ }
151
+
152
+ /*
153
+ * Run a mysql qeury
154
+ *
155
+ * name: query
156
+ * @param string $query Query to run
157
+ * @return $result or false
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{
169
+ return $result;
170
+ }
171
+
172
+ }
173
+
174
+
175
+ /*
176
+ * Returns an array of tables from a database and mark $2excluded ones
177
+ *
178
+ * name: lisTables
179
+ * @param array $excluded array of tables to mark as excluded
180
+ * @return array $tablesList
181
+ */
182
+ public function listTables($excluded){
183
+
184
+ $tablesList = array("");
185
+ $inc = 0;
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))
193
+ if( in_array($row[0], $excluded) )
194
+ $tablesList[$inc]['excluded'] = 1;
195
+ $inc++;
196
+ }
197
+
198
+ return $tablesList;
199
+
200
+ }
201
+
202
+ public function writeTempFile(){
203
+
204
+ $tables = self::listTables(self::$excludedTables);
205
+
206
+ $fp = fopen(self::$TEMP_DBPROCESS_FILE, "a");
207
+
208
+ if($fp){
209
+
210
+ fwrite($fp, sprintf("###newdump###\t%s\t%s\n", self::$dbDatabase, self::$TEMP_DUMP_FILE));
211
+
212
+ // write this to the class and write to $TEMP_DBPROCESS_FILE file as database.table records
213
+ foreach($tables as $key=>$table) if($table!= ""){
214
+
215
+ $tables[$key]['records'] = 0;
216
+
217
+ if(!$tables[$key]['excluded'])
218
+ $tables[$key]['records'] = self::countRecords($tables[$key]['table']);
219
+
220
+ $tmp = sprintf("`%s`.`%s`\t%s\t%s\n", self::$dbDatabase, $tables[$key]['table'], $tables[$key]['records'], $tables[$key]['excluded']);
221
+ fwrite($fp, $tmp);
222
+ }
223
+
224
+ fwrite($fp, "###enddump###\n");
225
+ fclose($fp);
226
+ }
227
+ else{
228
+ self::error("Unable to open for writing file ".self::$TEMP_DBPROCESS_FILE);
229
+ }
230
+
231
+ }
232
+
233
+ /*
234
+ * Returns the number of records from a table
235
+ *
236
+ * name: countRecords
237
+ * @param string $table - the source table
238
+ * @return int $count
239
+ */
240
+ public function countRecords($table){
241
+
242
+ $table = "`".self::$dbDatabase."`.`$table`";
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
+
250
+ }
251
+
252
+ /*
253
+ * Processing the mysql backup incrementally
254
+ *
255
+ * name: processIncremental
256
+ * @param
257
+ * int $startAtLine - at which line from the perm.txt file to start reading
258
+ * int startAtRecord - at which record to start from the table found at $startAtLine
259
+ * string $dumpfie - where to save the data
260
+ * string $dbCompatibility - MYSQL40, MYSQ32, none=default
261
+ * int $dbDropSyntax - check if the DROP TABLE syntax should be added
262
+ * @return array $return
263
+ */
264
+ public function processIncremental($startAtLine= 0, $startAtRecord = 0, $dumpfile = "", $dbCompatibility= "", $dbDropSyntax= ""){
265
+
266
+ $count = 0;
267
+ $return = array();
268
+
269
+ self::error("Starting new process at line $startAtLine from record $startAtRecord", 1);
270
+
271
+ $fp = fopen(self::$TEMP_DBPROCESS_FILE, "r");
272
+ if($fp){
273
+
274
+ while (($buffer = fgets($fp, 4096)) !== false){
275
+
276
+ if($count == $startAtLine){
277
+
278
+ $buffer = str_replace("\n", "", $buffer);
279
+ $tableInfo =explode("\t", $buffer);
280
+ //print_r($tableInfo);
281
+ if($tableInfo[0] == "###newdump###"){
282
+ // we create a new mysql dump file
283
+ if($dumpfile != ""){
284
+ // we finished a previous one and write the footers
285
+ $return['dumpsize'] = self::dataFooters($dumpfile);
286
+ }
287
+
288
+ $dump = fopen($tableInfo[2], "w");
289
+ fwrite($dump, self::dataHeaders($tableInfo[1]));
290
+ $startAtLine++;
291
+ fclose($dump);
292
+ $dumpfile = $tableInfo[2];
293
+
294
+ $return['newDump'] = 1;
295
+ //break;
296
+ }
297
+ else{
298
+ //we export the table
299
+ if($tableInfo[0] == "###enddump###")
300
+ $return['endDump'] = 1;
301
+
302
+ $fd = fopen($dumpfile, "a");
303
+
304
+ if($fd){
305
+
306
+ $next = $startAtRecord + self::$recordsPerSession;
307
+ // $tableInfo[1] number of records in the table
308
+ $table = explode("`.`", $tableInfo[0]);
309
+ $tableName = str_replace("`", "", $table[1]);
310
+ $databaseName = str_replace("`", "", $table[0]);
311
+
312
+ //return something to the browser
313
+ $return['tableName'] = $tableName;
314
+ $return['databaseName'] = $databaseName;
315
+ $return['totalRecords'] = $tableInfo[1];
316
+
317
+ //if(intval($return['totalRecords']) != 0)
318
+ if(trim($tableName) !="" and !$tableInfo[2])
319
+ self::exportTable($databaseName, $tableName, $startAtRecord, self::$recordsPerSession, $fd);
320
+
321
+ fclose($fd);
322
+
323
+ if($next > $tableInfo[1]) //we finished loading the records for next sessions, will go to the new record
324
+ {
325
+ $startAtLine ++;
326
+ $startAtRecord = 0;
327
+ }else{
328
+ $startAtRecord = $startAtRecord + self::$recordsPerSession;
329
+ }
330
+
331
+ //$return['dbCompatibility'] = self::$dbCompatibility;
332
+ //$return['dbDropSyntax'] = self::$dbDropSyntax;
333
+ $return['startAtLine'] = $startAtLine;
334
+ $return['startAtRecord'] = $startAtRecord;
335
+ $return['dumpfile'] = $dumpfile;
336
+
337
+ return $return;
338
+ break;
339
+
340
+ }else{
341
+ self::error("Unable to open for writing file $dumpfile");
342
+ }
343
+ }
344
+
345
+ }
346
+
347
+ $count++;
348
+
349
+
350
+ }
351
+
352
+ //while is finished, lets go home...
353
+ if($dumpfile != ""){
354
+ // we finished a previous one and write the footers
355
+ $return['dumpsize'] = self::dataFooters($dumpfile);
356
+ }
357
+ $return['finished'] = 1;
358
+ $return['startAtLine'] = $startAtLine;
359
+
360
+ return $return;
361
+
362
+ }else{
363
+ self::error("Unable to open for reading file ".self::$TEMP_DBPROCESS_FILE);
364
+ }
365
+
366
+
367
+ }
368
+
369
+
370
+ /*
371
+ * Exporting the table records
372
+ *
373
+ * name: exportTable
374
+ * @param
375
+ * string $databaseName - database name of the table
376
+ * string tableName - table name
377
+ * int $start - where to start from
378
+ * int $limit - how many records
379
+ * handler $fd - file handler where to write the records
380
+ * @return
381
+ */
382
+ public function exportTable($databaseName, $tableName, $start, $limit, $fd){
383
+
384
+ if($start == 0)
385
+ self::dumpStructure($databaseName, $tableName, $fd);
386
+
387
+ $start = intval($start);
388
+ $limit = intval($limit);
389
+ //exporting the table content now
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;
397
+ $buffer = "";
398
+ self::$countRecords++;
399
+
400
+ foreach ($arr as $key => $value) {
401
+ $value = mysql_real_escape_string($value);
402
+ $buffer .= "'".$value."', ";
403
+ }
404
+ $buffer = rtrim($buffer, ', ') . ");\n";
405
+ fwrite($fd, $buffer);
406
+ unset($buffer);
407
+
408
+ }
409
+ }
410
+
411
+ }
412
+
413
+ public function dumpStructure($databaseName, $tableName ,$fd){
414
+
415
+ fwrite($fd, "\n#\n# Table structure for table `$tableName`\n#\n\n");
416
+
417
+ if (self::$dbDropSyntax)
418
+ fwrite($fd, "\nDROP table IF EXISTS `$tableName`;\n");
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
+
426
+ fwrite($fd, "\n#\n# End Structure for table `$tableName`\n#\n\n");
427
+ fwrite($fd, "#\n# Dumping data for table `$tableName`\n#\n\n");
428
+ return;
429
+
430
+ }
431
+
432
+ public function dataFooters($dumpfile){
433
+
434
+ // we finished the dump file, not return the size of it
435
+ $ftemp = fopen($dumpfile, "a");
436
+ if($ftemp){
437
+ fwrite($ftemp, "\n#\n# Finished at: ".date("M j, Y \a\\t H:i")."\n#");
438
+ fclose($ftemp);
439
+ }else{
440
+ self::error("Unable to open file $ftemp for writing");
441
+ }
442
+
443
+ return sprintf("%u", filesize($dumpfile));
444
+
445
+ }
446
+
447
+ public function resetcountRecords(){
448
+ self::$countRecords = 0;
449
+
450
+ return self::$countRecords;
451
+ }
452
+
453
+ public function getcountRecords(){
454
+ return self::$countRecords;
455
+ }
456
+
457
+
458
+ public function dataHeaders($database){
459
+
460
+ $return = "";
461
+
462
+ $return .= "#\n";
463
+ $return .= "# Powered by XCloner Site Backup\n";
464
+ $return .= "# http://www.xcloner.com\n";
465
+ $return .= "#\n";
466
+ $return .= "# Host: " . $_SERVER['HTTP_HOST'] . "\n";
467
+ $return .= "# Generation Time: " . date("M j, Y \a\\t H:i") . "\n";
468
+ $return .= "# PHP Version: " . phpversion() . "\n";
469
+ $return .= "# Mysql Compatibility: ". self::$dbCompatibility . "\n";
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
+
477
+ }
478
+ }
479
+
480
+ $return .= "#\n# Database : `" . $database . "`\n# --------------------------------------------------------\n\n";
481
+ return $return;
482
+
483
+ }
484
+
485
+
486
+ }
487
+
488
+ ?>
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
@@ -39,6 +39,9 @@ $_CONFIG['sqldump']="mysqldump --quote-names ";
39
  $_CONFIG['system_dlink']="";
40
  $_CONFIG['system_ftptransfer']="0";
41
  $_CONFIG['system_mdatabases']="0";
 
 
 
42
 
43
  ### Defaults
44
  $script_dir = str_replace("\\","/",dirname(__FILE__));
39
  $_CONFIG['system_dlink']="";
40
  $_CONFIG['system_ftptransfer']="0";
41
  $_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__));
cloner.cron.php CHANGED
@@ -14,10 +14,38 @@
14
  @error_reporting(E_ALL^E_NOTICE);
15
  @set_time_limit('3600');
16
  define( '_VALID_MOS', 1 );
 
17
 
18
  include_once("admin.cloner.html.php");
19
  include_once("cloner.functions.php");
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
  $script_dir = str_replace("\\","/",dirname(__FILE__));
23
  if(is_dir($script_dir)){
@@ -31,12 +59,12 @@ if($_REQUEST['config'] == ""){
31
  if($argv[1] != ""){
32
 
33
  $_REQUEST['config'] = $argv[1];
34
-
35
  }
36
-
37
-
38
  }
39
 
 
 
 
40
  if($_REQUEST['config'] != ""){
41
 
42
  require_once( './configs/'.$_REQUEST['config'] );
@@ -82,7 +110,7 @@ else{
82
 
83
 
84
  ####### VERIFY IP ACCESS
85
- $ip_list = @explode("\r\n", $_CONFIG['cron_ip']);
86
  $ip_list[] = $_SERVER['SERVER_ADDR'];
87
  $curent_ip = $_SERVER["REMOTE_ADDR"];
88
 
@@ -91,7 +119,7 @@ if(!in_array($curent_ip, $ip_list)){
91
  echo "Access Denied for ip $curent_ip!";
92
  exit;
93
 
94
- }
95
  #########################
96
 
97
  $access=1;
@@ -169,89 +197,115 @@ $source_file = $clonerPath."/".$file;
169
  logxx("Backup file: ".$source_file);
170
  $bsize = getFileSizeText(filesize($source_file));
171
 
172
- if($_CONFIG['cron_send']==1){
173
- ######################################STARTING FTP TRANSFER##################
174
-
175
- logxx("Starting ftp transfer:");
176
-
177
- $source_files[] = $source_file;
178
- $destination_files[] = $_CONFIG[cron_ftp_path]."/".$file;
179
-
180
-
181
-
182
- // set up basic connection details
183
- list($fhost, $fport) = explode(":",$_CONFIG[cron_ftp_server]);
184
- if($fport == "")
185
- $fport = '21';
186
-
187
- $ftp_timeout = '3600';
188
-
189
- // set up basic connection
190
- if(!$_CONFIG[secure_ftp]){
191
- $conn_id = ftp_connect($fhost, (int)$fport, (int)$ftp_timeout);
192
- $connect = "Normal";
193
- }
194
- else{
195
- $conn_id = ftp_ssl_connect($fhost, (int)$fport, (int)$ftp_timeout);
196
- $connect = "Secure";
197
- }
198
-
199
- //$conn_id = ftp_connect($_CONFIG[cron_ftp_server]) or die("Could not connect to the ftp server ".$_CONFIG[cron_ftp_server]);
200
-
201
- // login with username and password
202
- $login_result = ftp_login($conn_id, $_CONFIG[cron_ftp_user], $_CONFIG[cron_ftp_pass])
203
- or die("Authentification failed when connecting to the ftp server for user ".$_CONFIG[cron_ftp_user]." with pass".$_CONFIG[cron_ftp_pass]);
204
-
205
- // check connection
206
- if ((!$conn_id) || (!$login_result)) {
207
- echo "<b style='color:red'>FTP connection has failed!</b>";
208
- echo "<b style='color:red'>Attempted to connect to ".$_CONFIG[cron_ftp_server]." for user ".$_CONFIG[cron_ftp_user]."</b>";
209
- return;
210
- } else {
211
- #echo "Connected to $_REQUEST[ftp_server], for user $_REQUEST[ftp_user]";
212
- }
213
-
214
- if($_CONFIG['system_ftptransfer']==1)
215
  {
216
- // turn passive mode on
217
- @ftp_pasv($conn_id, true);
218
- $mode = "Passive";
219
- }
220
- else
221
- {
222
- // turn passive mode off
223
- @ftp_pasv($conn_id, false);
224
- $mode = "Active";
225
- }
226
- echo "Connected to $connect <b>$_CONFIG[cron_ftp_server] Mode: $mode</b><br />";
227
- for($i=0;$i<sizeof($source_files);$i++)
228
- {
229
- // upload the file
230
- $upload = ftp_put($conn_id, $destination_files[$i], $source_files[$i], FTP_BINARY);
231
-
232
- // check upload status
233
- if (!$upload) {
234
- echo "<b style='color:red'>FTP upload has failed for file $source_files[$i] ! Stopping ....<br /></b>";return;
235
- } else {
236
- echo "<b>Upload success from file <i>$source_files[$i]</i> <br />to <i>$destination_files[$i]</i> ...<br /></b>";
237
- }
238
-
239
- }
240
-
241
- // close the FTP stream
242
- ftp_close($conn_id);
243
-
244
- logxx("Ftp transfer finished succesfully!");
245
-
246
- if($_CONFIG[cron_ftp_delb]==1){
247
-
248
- @unlink($source_file);
249
- logxx("Backup succesfully deleted from the original server!");
250
- }
251
 
252
- ##############################################################################
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
253
  }
254
- elseif($_CONFIG['cron_send']==2){
 
 
 
255
  #######################################STARTING Email TRANSFER################
256
  logxx("Sending mail with backup");
257
 
@@ -263,7 +317,7 @@ elseif($_CONFIG['cron_send']==2){
263
  Source Filename: $source_file
264
  Server: $mosConfig_live_site
265
 
266
- Powered by http://www.xcloner.com - Xcloner - Backup and Restore made easy!
267
  </pre>
268
 
269
  ";
@@ -288,9 +342,14 @@ include_once("classes/S3.php");
288
 
289
  logxx();
290
 
291
- $s3 = new S3($_CONFIG['cron_amazon_awsAccessKey'], $_CONFIG['cron_amazon_awsSecretKey']);
 
 
 
 
 
292
 
293
- logxx("AMAZON S3: Starting communication with the Amazon S3 server...");
294
 
295
  $buckets = $s3->listBuckets();
296
 
@@ -314,6 +373,63 @@ if (($s3->putBucket($_CONFIG['cron_amazon_bucket'], "private")) || (@in_array($_
314
 
315
 
316
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
317
  }
318
  ###### END
319
 
@@ -331,6 +447,12 @@ delete_older_backups($clonerPath);
331
  ###################END OLDER BACKUPS
332
 
333
  $logemail = explode(";", $_CONFIG['cron_logemail']);
 
 
 
 
 
 
334
  if(sizeof($logemail)>0){
335
 
336
  for($i=0; $i<sizeof($logemail);$i++){
@@ -340,7 +462,7 @@ if(sizeof($logemail)>0){
340
 
341
  $email_subject = "cron log ".time();
342
 
343
- $headers ="From: \"Cronlog XCloner\" <nobody@noreply.com>\n";
344
 
345
  if(mail($email, $email_subject, strip_tags($mail_log), $headers)){
346
 
@@ -449,3 +571,21 @@ return $ok;
449
 
450
  }
451
  ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  @error_reporting(E_ALL^E_NOTICE);
15
  @set_time_limit('3600');
16
  define( '_VALID_MOS', 1 );
17
+ header('Content-Type: text/html; charset=utf-8');
18
 
19
  include_once("admin.cloner.html.php");
20
  include_once("cloner.functions.php");
21
 
22
+ require_once( 'cloner.config.php' );
23
+
24
+ ####### VERIFY IP ACCESS
25
+ function check_user_ip($current_ip, $ip_list)
26
+ {
27
+ $valid = FALSE;
28
+
29
+ foreach ($ip_list as $ip){
30
+ $ip_or_name = gethostbyname($ip);
31
+ if ($current_ip == $ip_or_name) {
32
+ $valid = TRUE;
33
+ break;
34
+ }
35
+ }
36
+
37
+ return $valid;
38
+ }
39
+
40
+ $ip_list = @explode("\r\n", $_CONFIG['cron_ip']);
41
+ $ip_list[] = $_SERVER['SERVER_ADDR'];
42
+ $curent_ip = $_SERVER["REMOTE_ADDR"];
43
+
44
+ if (check_user_ip($curent_ip, $ip_list) == FALSE) {
45
+ echo "Access Denied for ip $curent_ip!";
46
+ exit;
47
+ }
48
+ #########################
49
 
50
  $script_dir = str_replace("\\","/",dirname(__FILE__));
51
  if(is_dir($script_dir)){
59
  if($argv[1] != ""){
60
 
61
  $_REQUEST['config'] = $argv[1];
 
62
  }
 
 
63
  }
64
 
65
+ //filter the config request path
66
+ $_REQUEST['config'] = str_replace(array("..","/","\\"), array("","",""), trim($_REQUEST['config']));
67
+
68
  if($_REQUEST['config'] != ""){
69
 
70
  require_once( './configs/'.$_REQUEST['config'] );
110
 
111
 
112
  ####### VERIFY IP ACCESS
113
+ /*$ip_list = @explode("\r\n", $_CONFIG['cron_ip']);
114
  $ip_list[] = $_SERVER['SERVER_ADDR'];
115
  $curent_ip = $_SERVER["REMOTE_ADDR"];
116
 
119
  echo "Access Denied for ip $curent_ip!";
120
  exit;
121
 
122
+ }*/
123
  #########################
124
 
125
  $access=1;
197
  logxx("Backup file: ".$source_file);
198
  $bsize = getFileSizeText(filesize($source_file));
199
 
200
+ if($_CONFIG['cron_send']==1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  {
202
+ ######################################STARTING FTP TRANSFER##################
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
 
204
+ $source_files[] = $source_file;
205
+ $destination_files[] = $_CONFIG[cron_ftp_path]."/".$file;
206
+
207
+ // set up basic connection details
208
+ list($fhost, $fport) = explode(":",$_CONFIG[cron_ftp_server]);
209
+ if($fport == "")
210
+ $fport = '21';
211
+
212
+ $ftp_timeout = '3600';
213
+
214
+ logxx("Starting ftp transfer:");
215
+ if(!$_CONFIG[secure_ftp])
216
+ {
217
+ // set up basic connection
218
+ $conn_id = ftp_connect($fhost, (int)$fport, (int)$ftp_timeout);
219
+ $connect = "Normal";
220
+
221
+ // login with username and password
222
+ $login_result = ftp_login($conn_id, $_CONFIG[cron_ftp_user], $_CONFIG[cron_ftp_pass])
223
+ or die("Authentification failed when connecting to the ftp server for user ".$_CONFIG[cron_ftp_user]." with pass".$_CONFIG[cron_ftp_pass]);
224
+
225
+ // check connection
226
+ if ((!$conn_id) || (!$login_result)) {
227
+ echo "<b style='color:red'>FTP connection has failed!</b>";
228
+ echo "<b style='color:red'>Attempted to connect to ".$_CONFIG[cron_ftp_server]." for user ".$_CONFIG[cron_ftp_user]."</b>";
229
+ return;
230
+ } else {
231
+ #echo "Connected to $_REQUEST[ftp_server], for user $_REQUEST[ftp_user]";
232
+ }
233
+
234
+ if($_CONFIG['system_ftptransfer']==1)
235
+ {
236
+ // turn passive mode on
237
+ @ftp_pasv($conn_id, true);
238
+ $mode = "Passive";
239
+ }
240
+ else
241
+ {
242
+ // turn passive mode off
243
+ @ftp_pasv($conn_id, false);
244
+ $mode = "Active";
245
+ }
246
+ echo "Connected to $connect <b>$_CONFIG[cron_ftp_server] Mode: $mode</b><br />";
247
+ for($i=0;$i<sizeof($source_files);$i++)
248
+ {
249
+ // upload the file
250
+ $upload = ftp_put($conn_id, $destination_files[$i], $source_files[$i], FTP_BINARY);
251
+
252
+ // check upload status
253
+ if (!$upload) {
254
+ echo "<b style='color:red'>FTP upload has failed for file $source_files[$i] ! Stopping ....<br /></b>";return;
255
+ } else {
256
+ echo "<b>Upload success from file <i>$source_files[$i]</i> <br />to <i>$destination_files[$i]</i> ...<br /></b>";
257
+ }
258
+ }
259
+
260
+ // close the FTP stream
261
+ ftp_close($conn_id);
262
+ }
263
+ else //Use sftp
264
+ {
265
+ //set php path to include required sftp files
266
+ set_include_path(get_include_path() . PATH_SEPARATOR .'classes/phpseclib');
267
+
268
+ include('Net/SFTP.php');
269
+ //define('NET_SFTP_LOGGING', NET_SFTP_LOG_COMPLEX); // or NET_SFTP_LOG_SIMPLE
270
+
271
+ //connect to host and authenticate user
272
+ $sftp = new Net_SFTP($fhost);
273
+ if (!$sftp->login($_CONFIG[cron_ftp_user], $_CONFIG[cron_ftp_pass]))
274
+ {
275
+ logxx('Login Failed');
276
+ die("Login Failed");
277
+ }
278
+ logxx("Connected to $connect <b>$_CONFIG[cron_ftp_server] Successfully!><br />");
279
+
280
+ //transfere files
281
+ for($i=0;$i<sizeof($source_files);$i++)
282
+ {
283
+ // upload the file
284
+ $upload = $sftp->put($destination_files[$i], $source_files[$i], NET_SFTP_LOCAL_FILE);
285
+
286
+ // check upload status
287
+ if (!$upload) {
288
+ logxx("<b style='color:red'>FTP upload has failed for file $source_files[$i] ! Stopping ....<br /></b>");return;
289
+ } else {
290
+ logxx("<b>Upload success from file <i>$source_files[$i]</i> <br />to <i>$destination_files[$i]</i> ...<br /></b>");
291
+ }
292
+ }
293
+
294
+ //disconnect from server
295
+ unset($sftp);
296
+ }
297
+
298
+ logxx("Ftp transfer finished succesfully!");
299
+
300
+ if($_CONFIG[cron_ftp_delb]==1)
301
+ {
302
+ @unlink($source_file);
303
+ logxx("Backup succesfully deleted from the original server!");
304
  }
305
+ ##############################################################################
306
+ }
307
+ else if($_CONFIG['cron_send']==2)
308
+ {
309
  #######################################STARTING Email TRANSFER################
310
  logxx("Sending mail with backup");
311
 
317
  Source Filename: $source_file
318
  Server: $mosConfig_live_site
319
 
320
+ Powered by http://www.xcloner.com - XCloner - Backup and Restore made easy!
321
  </pre>
322
 
323
  ";
342
 
343
  logxx();
344
 
345
+ if(!$_CONFIG['cron_amazon_ssl'])
346
+ $amazon_ssl = false;
347
+ else
348
+ $amazon_ssl = true;
349
+
350
+ $s3 = new S3($_CONFIG['cron_amazon_awsAccessKey'], $_CONFIG['cron_amazon_awsSecretKey'], $amazon_ssl);
351
 
352
+ logxx("AMAZON S3: Starting communication with the Amazon S3 server...ssl mode ".(int)$amazon_ssl);
353
 
354
  $buckets = $s3->listBuckets();
355
 
373
 
374
 
375
 
376
+ }
377
+ ###### END
378
+
379
+ ####### STARING DROPBOX MODE
380
+ if($_CONFIG['cron_dropbox_active']){
381
+
382
+ include_once("classes/DropboxClient.php");
383
+
384
+ $dropbox = new DropboxClient(array(
385
+ 'app_key' => $_CONFIG['cron_dropbox_Key'],
386
+ 'app_secret' => $_CONFIG['cron_dropbox_Secret'],
387
+ 'app_full_access' => false,
388
+ ),'en');
389
+
390
+ logxx();
391
+
392
+ logxx("DROPBOX: Starting communication with the DropBox server...");
393
+
394
+ // first try to load existing access token
395
+ $access_token = load_token("access");
396
+ if(!empty($access_token)) {
397
+ $dropbox->SetAccessToken($access_token);
398
+ //print_r($access_token);
399
+ }
400
+ elseif(!empty($_GET['auth_callback'])) // are we coming from dropbox's auth page?
401
+ {
402
+ // then load our previosly created request token
403
+ $request_token = load_token($_GET['oauth_token']);
404
+ if(empty($request_token)) die('Request token not found!');
405
+
406
+ // get & store access token, the request token is not needed anymore
407
+ $access_token = $dropbox->GetAccessToken($request_token);
408
+ store_token($access_token, "access");
409
+ delete_token($_GET['oauth_token']);
410
+ }
411
+
412
+ // checks if access token is required
413
+ if(!$dropbox->IsAuthorized())
414
+ {
415
+ // redirect user to dropbox auth page
416
+ $return_url = "http://".$_SERVER['HTTP_HOST'].$_SERVER['SCRIPT_NAME']."?auth_callback=1";
417
+ $auth_url = $dropbox->BuildAuthorizeUrl($return_url);
418
+ $request_token = $dropbox->GetRequestToken();
419
+ store_token($request_token, $request_token['t']);
420
+ die("Authentication required. <a href='$auth_url'>Click here.</a>");
421
+ }
422
+
423
+
424
+
425
+ $return = $dropbox->UploadFile($clonerPath."/".$file, $_CONFIG['cron_dropbox_dirname']."/".$file);
426
+ if($return->error)
427
+ logxx($return->error);
428
+ else
429
+ logxx("File copied to ".$return->path);
430
+
431
+ #print_r($return);
432
+
433
  }
434
  ###### END
435
 
447
  ###################END OLDER BACKUPS
448
 
449
  $logemail = explode(";", $_CONFIG['cron_logemail']);
450
+
451
+ if($_CONFIG['cron_fromlogemail'])
452
+ $fromemail = $_CONFIG['cron_fromlogemail'];
453
+ else
454
+ $fromemail = "nobody@noreply.com";
455
+
456
  if(sizeof($logemail)>0){
457
 
458
  for($i=0; $i<sizeof($logemail);$i++){
462
 
463
  $email_subject = "cron log ".time();
464
 
465
+ $headers ="From: \"XCloner Cron Log Output\" <".$fromemail.">\n";
466
 
467
  if(mail($email, $email_subject, strip_tags($mail_log), $headers)){
468
 
571
 
572
  }
573
  ?>
574
+ <?php
575
+ function store_token($token, $name)
576
+ {
577
+ if(!file_put_contents("tokens/$name.token", serialize($token)))
578
+ die('<br />Could not store token! <b>Make sure that the directory `tokens` exists and is writable!</b>');
579
+ }
580
+
581
+ function load_token($name)
582
+ {
583
+ if(!file_exists("tokens/$name.token")) return null;
584
+ return @unserialize(@file_get_contents("tokens/$name.token"));
585
+ }
586
+
587
+ function delete_token($name)
588
+ {
589
+ @unlink("tokens/$name.token");
590
+ }
591
+ ?>
cloner.functions.php CHANGED
@@ -20,14 +20,16 @@
20
  * MA 02110-1301, USA.
21
  */
22
 
 
 
 
 
23
  /*
24
  * Process the logout request
25
  * name: doLogout()
26
  * @param
27
  * @return
28
  */
29
-
30
- /*processing the Logout task*/
31
  function doLogout()
32
  {
33
  if (function_exists('session_unregister')) {
@@ -121,7 +123,8 @@
121
 
122
  function fdefault()
123
  {
124
- HTML_cloner::_FDefault();
 
125
  }
126
 
127
  function config($option)
@@ -139,13 +142,13 @@
139
  if ($fp = @fopen($config_file, 'w')) {
140
  $cfg = '<?' . 'php' . "\n";
141
 
142
- $cfg .= '$_CONFIG[\'license_code\']="' . $_REQUEST[license_code] . '";' . "\n";
143
 
144
  $cfg .= '$_CONFIG[\'backup_path\']="' . $_REQUEST[backup_path] . '";' . "\n";
145
 
146
  $cfg .= '$_CONFIG[\'clonerPath\']="' . $_REQUEST[clonerPath] . '";' . "\n";
147
 
148
- $cfg .= '$_CONFIG[\'jcuser\']="' . $_REQUEST[jcuser] . '";' . "\n";
149
 
150
  if ($_REQUEST['jcpass'] == '') {
151
  $jcpass = $_CONFIG['jcpass'];
@@ -159,7 +162,7 @@
159
 
160
  $cfg .= '$_CONFIG[\'mysql_host\']="' . $_REQUEST[mysql_host] . '";' . "\n";
161
 
162
- $cfg .= '$_CONFIG[\'mysql_user\']="' . $_REQUEST[mysql_user] . '";' . "\n";
163
 
164
  $cfg .= '$_CONFIG[\'mysql_pass\']=\'' . $_REQUEST[mysql_pass] . '\';' . "\n";
165
 
@@ -174,6 +177,8 @@
174
  $cfg .= '$_CONFIG[\'backup_compress\']="' . $_REQUEST[backup_compress] . '";' . "\n";
175
 
176
  $cfg .= '$_CONFIG[\'cron_logemail\']="' . $_REQUEST[cron_logemail] . '";' . "\n";
 
 
177
 
178
  $cfg .= '$_CONFIG[\'cron_exclude\']="' . $_REQUEST[cron_exclude] . '";' . "\n";
179
 
@@ -187,7 +192,7 @@
187
 
188
  $cfg .= '$_CONFIG[\'cron_ftp_server\']="' . $_REQUEST[cron_ftp_server] . '";' . "\n";
189
 
190
- $cfg .= '$_CONFIG[\'cron_ftp_user\']="' . $_REQUEST[cron_ftp_user] . '";' . "\n";
191
 
192
  $cfg .= '$_CONFIG[\'cron_ftp_pass\']=\'' . $_REQUEST[cron_ftp_pass] . '\';' . "\n";
193
 
@@ -213,6 +218,12 @@
213
 
214
  $cfg .= '$_CONFIG[\'refresh_mode\']="' . $_REQUEST[refresh_mode] . '";' . "\n";
215
 
 
 
 
 
 
 
216
  $cfg .= '$_CONFIG[\'backup_refresh_number\']="' . $_REQUEST[backup_refresh_number] . '";' . "\n";
217
 
218
  $cfg .= '$_CONFIG[\'sql_mem\']="' . $_REQUEST[sql_mem] . '";' . "\n";
@@ -237,13 +248,23 @@
237
 
238
  $cfg .= '$_CONFIG[\'cron_amazon_active\']="' . $_REQUEST[cron_amazon_active] . '";' . "\n";
239
 
240
- $cfg .= '$_CONFIG[\'cron_amazon_awsAccessKey\']="' . $_REQUEST[cron_amazon_awsAccessKey] . '";' . "\n";
241
 
242
- $cfg .= '$_CONFIG[\'cron_amazon_awsSecretKey\']="' . $_REQUEST[cron_amazon_awsSecretKey] . '";' . "\n";
243
 
244
- $cfg .= '$_CONFIG[\'cron_amazon_bucket\']="' . $_REQUEST[cron_amazon_bucket] . '";' . "\n";
245
 
246
- $cfg .= '$_CONFIG[\'cron_amazon_dirname\']="' . $_REQUEST[cron_amazon_dirname] . '";' . "\n";
 
 
 
 
 
 
 
 
 
 
247
 
248
  $cfg .= '$_CONFIG[\'debug\']="' . $_REQUEST[debug] . '";' . "\n";
249
 
@@ -266,7 +287,7 @@
266
  } else {
267
 
268
 
269
- $msg = "Unable to save $fcron file, please make sure the folder is writeable!";
270
  }
271
  }
272
 
@@ -278,7 +299,8 @@
278
  E_print($msg);
279
  }
280
  }
281
- HTML_cloner::Config($option);
 
282
  }
283
 
284
  //## JoomlaCloner Language Manager
@@ -304,7 +326,8 @@
304
  mosRedirect('index2.php?option=' . $option . "&task=lang", $msg);
305
  }
306
 
307
- HTML_cloner::Translator($option, $lang_array);
 
308
  }
309
 
310
  function translator_add($option, $task)
@@ -330,9 +353,9 @@
330
 
331
  mosRedirect('index2.php?option=' . $option . "&task=lang", $msg);
332
  }
333
-
334
-
335
- HTML_cloner::Translator_Add($option);
336
  }
337
  function translator_edit($option, $task)
338
  {
@@ -414,14 +437,15 @@
414
 
415
 
416
  if ($lang == 'english') {
417
- HTML_cloner::Translator_Edit_DEFAULT($option, $content, $file, $lang);
 
418
  } else {
419
  $def_data = get_lang_data($dfile);
420
  $cur_data = get_lang_data($file);
421
 
422
  $data = array_merge($def_data, $cur_data);
423
-
424
- HTML_cloner::Translator_Edit($option, $data, $def_data, $file, $lang);
425
  }
426
  }
427
 
@@ -469,11 +493,103 @@
469
  return $lang_arr;
470
  }
471
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
472
 
473
  function goRecurseFiles(){
474
 
475
  global $_CONFIG;
476
-
477
  include_once("classes/fileRecursion.php");
478
 
479
  $status['finished'] = "1";
@@ -481,16 +597,18 @@
481
 
482
  $handle = new fileRecursion();
483
 
484
- $TEMP_PERM = $_CONFIG['backups_dir']."/perm.txt";
485
- $TEMP_EXCL = $_CONFIG['exfile'];
486
- $TEMP_D_ARR = $_CONFIG['backups_dir']."/.dir";
487
- $TEMP_DIR = $_CONFIG['clonerPath'];
488
- $START_DIR = $_CONFIG['backup_path'];
 
 
489
 
490
- $handle->setData($TEMP_PERM,$TEMP_EXCL,$TEMP_D_ARR,$TEMP_DIR, $START_DIR);
491
 
492
  if($_REQUEST['mode'] == 'start')
493
- $handle->init($_CONFIG['backup_path']);
494
  else
495
  $handle->init();
496
 
@@ -505,10 +623,15 @@
505
 
506
  if(!$handle->isQueueFinished())
507
  $status['finished'] = "0";
508
-
509
-
 
 
 
 
510
 
511
  echo json_encode($status);
 
512
  exit;
513
 
514
  }
@@ -537,7 +660,8 @@
537
  getBackupFiles($d_arr, $f_arr, $s_arr, $d, $f);
538
 
539
  // load presentation layer
540
- HTML_cloner::showBackups($f_arr, $s_arr, $_CONFIG['clonerPath'], $option);
 
541
  }
542
 
543
  function moveBackup($option)
@@ -553,8 +677,10 @@
553
  if ($_REQUEST['action'] == "connect") {
554
  $ret = start_connect($_REQUEST[files]);
555
  }
556
- if (!$ret)
557
- HTML_cloner::TransferForm($option, $files_out);
 
 
558
  }
559
 
560
  function start_connect($files)
@@ -786,14 +912,14 @@
786
  }
787
 
788
 
789
-
790
- HTML_Cloner::rename($files, $option);
791
  }
792
  function downloadBackup($file)
793
  {
794
  global $_CONFIG;
795
 
796
- $file = $_CONFIG['clonerPath'] . "/$file";
797
 
798
  //First, see if the file exists
799
  if (!is_file($file)) {
@@ -807,75 +933,66 @@
807
 
808
  //Setam Content-Type-urile pentru fisierul in cauza
809
  switch ($file_extension) {
810
- case "pdf":
811
- $ctype = "application/pdf";
812
- break;
813
- case "exe":
814
- $ctype = "application/octet-stream";
815
- break;
816
- case "zip":
817
- $ctype = "application/zip";
818
- break;
819
- case "doc":
820
- $ctype = "application/msword";
821
- break;
822
- case "xls":
823
- $ctype = "application/vnd.ms-excel";
824
- break;
825
- case "ppt":
826
- $ctype = "application/vnd.ms-powerpoint";
827
- break;
828
- case "gif":
829
- $ctype = "image/gif";
830
- break;
831
- case "png":
832
- $ctype = "image/png";
833
- break;
834
- case "jpeg":
835
- case "jpg":
836
- $ctype = "image/jpg";
837
- break;
838
- case "mp3":
839
- $ctype = "audio/mpeg";
840
- break;
841
- case "wav":
842
- $ctype = "audio/x-wav";
843
- break;
844
- case "mpeg":
845
- case "mpg":
846
- case "mpe":
847
- $ctype = "video/mpeg";
848
- break;
849
- case "mov":
850
- $ctype = "video/quicktime";
851
- break;
852
- case "avi":
853
- $ctype = "video/x-msvideo";
854
- break;
855
-
856
  default:
857
  $ctype = "application/force-download";
858
  }
859
 
860
- //Writing Headers
861
- header("Pragma: public");
862
- header("Expires: 0");
863
- header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
864
- header("Cache-Control: public");
865
- header("Content-Description: File Transfer");
866
-
867
- //Content-Type-ul
868
- header("Content-Type: $ctype");
869
 
870
- //Force Download
871
- $header = "Content-Disposition: attachment; filename=" . $filename . ";";
872
- header($header);
873
- header("Content-Transfer-Encoding: binary");
874
- header("Content-Length: " . $len);
875
- @readfile($file);
876
  exit;
877
  }
878
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
879
 
880
  function confirmBackup($option)
881
  {
@@ -925,9 +1042,10 @@
925
  }
926
 
927
  // load presentation layer
928
- if ($option != 'nohtml')
929
- HTML_cloner::confirmBackups($d_arr, $ds_arr, $_CONFIG['clonerPath'], $option);
930
- else
 
931
  return $d_arr;
932
  }
933
 
@@ -965,9 +1083,9 @@
965
 
966
  $log = "";
967
 
968
- $backup_file = $_CONFIG['clonerPath']."/".$backup_filename ;
969
 
970
- $perm_file = $_CONFIG['backups_dir'] . "/perm.txt";
971
 
972
 
973
  $lines = $_REQUEST['lines'];
@@ -991,7 +1109,6 @@
991
 
992
  $url = "index2.php?option=com_cloner&task=refresh&json=$json&startf=$endf&lines=$lines&backup=$backup_filename&excl_manual=" . $_REQUEST['excl_manual'];
993
 
994
-
995
  if ($endf >= $lines)
996
  $endf = $lines;
997
  else
@@ -1000,7 +1117,6 @@
1000
  if ((int)$lines != 0)
1001
  $percent = sprintf("%d", ($endf * 100) / (int)$lines);
1002
 
1003
-
1004
  $log .= "Total process: $percent% out of $lines files<br />\n";
1005
  $log .= "Processing files $startf to $endf for backup file $backup_file!<br />\n";
1006
  $log .= "Current backup size: " . getFileSizeText(get_filesize($backup_file)) . "<br /><br />\n";
@@ -1013,7 +1129,7 @@
1013
 
1014
  $buffer = explode("|", fgets($fperm, 4096));
1015
 
1016
- if (($line < $endf) && ($line >= $startf)) {
1017
  $log .= "\n<br />$line. ";
1018
 
1019
  if (($buffer[0] != "") && (is_file($buffer[0]))) {
@@ -1022,6 +1138,23 @@
1022
  //## appending files
1023
  $log .= "file - $file";
1024
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1025
 
1026
  if (!$_CONFIG['mem']) {
1027
  //### CREATE BACKUP USING TAR LIBRARIES
@@ -1055,7 +1188,7 @@
1055
  }
1056
 
1057
  //exit;
1058
- $newFileSize = getFileSizeText(get_filesize($backup_file));
1059
  $log .= "\n<br />New backup size: " . $newFileSize . "<br />\n";
1060
 
1061
  addXLog($log);
@@ -1070,21 +1203,21 @@
1070
  //# REDIRECTING
1071
  @fclose($fperm);
1072
 
1073
- $log .= "<br>All done, redirecting in " . $_CONFIG['refresh_time'] . " seconds, or <a href='$url'>click here </a>";
1074
 
1075
  $log .= "
1076
- <script language='javascript'>
1077
- function redirect(){
1078
- window.location = '" . $url . "';
1079
- }
1080
 
1081
- setTimeout(\"redirect()\"," . $_CONFIG['refresh_time'] . "000);
 
1082
 
1083
- </script>";
1084
  }
1085
- } else {
1086
-
1087
 
 
1088
  $log .= "Unable to continue, could not open file $perm_file for reading!";
1089
  }
1090
 
@@ -1098,10 +1231,10 @@
1098
  $status['finished'] = 1;
1099
  }
1100
 
1101
- if(!$json){
1102
- echo $log;
1103
  }
1104
- else{
1105
  $status['backupSize'] = $newFileSize;
1106
  $status['percent'] = $percent;
1107
  $status['option'] = 'com_cloner';
@@ -1115,7 +1248,7 @@
1115
  echo json_encode($status);
1116
  exit;
1117
 
1118
- }
1119
 
1120
  return;
1121
  }
@@ -1134,9 +1267,7 @@
1134
  if (!$_CONFIG['enable_db_backup']) {
1135
  $backupDatabase = 0;
1136
  } else {
1137
-
1138
-
1139
- $backupDatabase = $_REQUEST['dbbackup'];
1140
  }
1141
 
1142
  if ($_REQUEST[cron_access]) {
@@ -1173,8 +1304,6 @@
1173
  $f_ext = '.tgz';
1174
  $_CONFIG['tarcompress'] = 'z';
1175
  } else {
1176
-
1177
-
1178
  $f_ext = '.tar';
1179
  $_CONFIG['tarcompress'] = '';
1180
  }
@@ -1204,6 +1333,15 @@
1204
  $filename1 = $_REQUEST['bname'] . $f_ext;
1205
  }
1206
 
 
 
 
 
 
 
 
 
 
1207
  $sql_file = array();
1208
 
1209
  if ($backupDatabase == 1) {
@@ -1231,7 +1369,7 @@
1231
  mysql_query("USE " . $_CONFIG['mysql_database']);
1232
  }
1233
  } else {
1234
- $databaseResult = LM_DATABASE_EXCLUDED;
1235
  }
1236
 
1237
 
@@ -1324,22 +1462,24 @@
1324
 
1325
  if(($_REQUEST['cron_access']) or (!$_CONFIG['refresh_mode'])){
1326
 
1327
- $perm_file = $_CONFIG['backups_dir'] . "/perm.txt";
1328
- @unlink($perm_file);
1329
- $fperm = fopen($perm_file, "w");
1330
 
1331
- for ($i = 0; $i < sizeof($excluded); $i++) {
1332
- $excluded[$i] = str_replace("//", "/", $excluded[$i]);
1333
- }
1334
 
1335
- // obtain the list of files by recursing the mambo file store
1336
- addXLog("Starting the file scanning process");
1337
 
1338
- recurseFiles($d_arr, $ds_arr, $f_arr, $s_arr, $d, $f, $s, $includeFolder, '', $excluded, $fperm);
1339
- @fclose($fperm);
1340
- @chmod($perm_file, 0777);
1341
 
1342
- }
 
 
 
 
1343
 
1344
 
1345
  // format total archive size
@@ -1395,6 +1535,9 @@
1395
 
1396
  if ($_CONFIG['backup_refresh']) {
1397
  $f_arr = array($_CONFIG['backups_dir'] . "/index.html");
 
 
 
1398
  }
1399
 
1400
 
@@ -1417,9 +1560,10 @@
1417
 
1418
  if ($_CONFIG['backup_refresh']) {
1419
  // echo "Starting the manual backup process!<br />";
1420
- echo "<h3>Database backup: </h3>" . $databaseResult . "<br /><br />";
1421
-
1422
- HTML_cloner::goRefreshHtml($filename, $perm_lines, $excl_manual);
 
1423
  return;
1424
  }
1425
 
@@ -1511,8 +1655,8 @@
1511
  E_print("Backup failed, please check your tar server utility support!");
1512
  return;
1513
  }*/
1514
-
1515
- HTML_cloner::goRefreshHtml($filename, $perm_lines, $excl_manual);
1516
 
1517
  return;
1518
  }
@@ -1554,11 +1698,12 @@
1554
 
1555
  // load presentation layer
1556
  if ($option != 'nohtml') {
1557
- HTML_cloner::generateBackup($filename1, $archiveSize, $originalSize, $mdir, $f, $databaseResult, $option);
 
1558
  } else {
1559
 
1560
-
1561
- logxx(HTML_cloner::generateBackup_text($filename1, $archiveSize, $originalSize, $mdir, $f, $databaseResult, $option));
1562
  }
1563
 
1564
  if (is_array($databases_incl)) {
@@ -1582,7 +1727,8 @@
1582
  // ----------------------------------------------------------
1583
 
1584
  // load presentation layer
1585
- HTML_cloner::showHelp($option);
 
1586
  }
1587
 
1588
 
@@ -1925,9 +2071,9 @@
1925
  $InsertDump = "INSERT INTO `$tblval` VALUES (";
1926
  $arr = $row;
1927
  foreach ($arr as $key => $value) {
1928
- $value = addslashes($value);
1929
- $value = str_replace("\n", '\r\n', $value);
1930
- $value = str_replace("\r", '', $value);
1931
  //if (@preg_match ("/\b" . $FieldType[$tblval][$key] . "\b/i", "DATE TIME DATETIME CHAR VARCHAR TEXT TINYTEXT MEDIUMTEXT LONGTEXT BLOB TINYBLOB MEDIUMBLOB LONGBLOB ENUM SET"))
1932
  {
1933
  $InsertDump .= "'$value',";
@@ -1956,11 +2102,46 @@
1956
  }
1957
  }
1958
 
 
1959
 
1960
- function getVersion()
1961
- {
1962
- $query = mysql_query("SELECT version()");
1963
- $row = mysql_fetch_array($query);
1964
- return $row[0];
1965
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1966
  ?>
20
  * MA 02110-1301, USA.
21
  */
22
 
23
+ /** ensure this file is being included by a parent file */
24
+ defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
25
+
26
+
27
  /*
28
  * Process the logout request
29
  * name: doLogout()
30
  * @param
31
  * @return
32
  */
 
 
33
  function doLogout()
34
  {
35
  if (function_exists('session_unregister')) {
123
 
124
  function fdefault()
125
  {
126
+ $html = new HTML_cloner();
127
+ $html->_FDefault();
128
  }
129
 
130
  function config($option)
142
  if ($fp = @fopen($config_file, 'w')) {
143
  $cfg = '<?' . 'php' . "\n";
144
 
145
+ $cfg .= '$_CONFIG[\'license_code\']=\'' . $_REQUEST[license_code] . '\';' . "\n";
146
 
147
  $cfg .= '$_CONFIG[\'backup_path\']="' . $_REQUEST[backup_path] . '";' . "\n";
148
 
149
  $cfg .= '$_CONFIG[\'clonerPath\']="' . $_REQUEST[clonerPath] . '";' . "\n";
150
 
151
+ $cfg .= '$_CONFIG[\'jcuser\']=\'' . $_REQUEST[jcuser] . '\';' . "\n";
152
 
153
  if ($_REQUEST['jcpass'] == '') {
154
  $jcpass = $_CONFIG['jcpass'];
162
 
163
  $cfg .= '$_CONFIG[\'mysql_host\']="' . $_REQUEST[mysql_host] . '";' . "\n";
164
 
165
+ $cfg .= '$_CONFIG[\'mysql_user\']=\'' . $_REQUEST[mysql_user] . '\';' . "\n";
166
 
167
  $cfg .= '$_CONFIG[\'mysql_pass\']=\'' . $_REQUEST[mysql_pass] . '\';' . "\n";
168
 
177
  $cfg .= '$_CONFIG[\'backup_compress\']="' . $_REQUEST[backup_compress] . '";' . "\n";
178
 
179
  $cfg .= '$_CONFIG[\'cron_logemail\']="' . $_REQUEST[cron_logemail] . '";' . "\n";
180
+
181
+ $cfg .= '$_CONFIG[\'cron_fromlogemail\']="' . $_REQUEST[cron_fromlogemail] . '";' . "\n";
182
 
183
  $cfg .= '$_CONFIG[\'cron_exclude\']="' . $_REQUEST[cron_exclude] . '";' . "\n";
184
 
192
 
193
  $cfg .= '$_CONFIG[\'cron_ftp_server\']="' . $_REQUEST[cron_ftp_server] . '";' . "\n";
194
 
195
+ $cfg .= '$_CONFIG[\'cron_ftp_user\']=\'' . $_REQUEST[cron_ftp_user] . '\';' . "\n";
196
 
197
  $cfg .= '$_CONFIG[\'cron_ftp_pass\']=\'' . $_REQUEST[cron_ftp_pass] . '\';' . "\n";
198
 
218
 
219
  $cfg .= '$_CONFIG[\'refresh_mode\']="' . $_REQUEST[refresh_mode] . '";' . "\n";
220
 
221
+ $cfg .= '$_CONFIG[\'recordsPerSession\']="' . $_REQUEST[recordsPerSession] . '";' . "\n";
222
+
223
+ $cfg .= '$_CONFIG[\'excludeFilesSize\']="' . $_REQUEST[excludeFilesSize] . '";' . "\n";
224
+
225
+ $cfg .= '$_CONFIG[\'splitBackupSize\']="' . $_REQUEST[splitBackupSize] . '";' . "\n";
226
+
227
  $cfg .= '$_CONFIG[\'backup_refresh_number\']="' . $_REQUEST[backup_refresh_number] . '";' . "\n";
228
 
229
  $cfg .= '$_CONFIG[\'sql_mem\']="' . $_REQUEST[sql_mem] . '";' . "\n";
248
 
249
  $cfg .= '$_CONFIG[\'cron_amazon_active\']="' . $_REQUEST[cron_amazon_active] . '";' . "\n";
250
 
251
+ $cfg .= '$_CONFIG[\'cron_amazon_awsAccessKey\']=\'' . $_REQUEST[cron_amazon_awsAccessKey] . '\';' . "\n";
252
 
253
+ $cfg .= '$_CONFIG[\'cron_amazon_awsSecretKey\']=\'' . $_REQUEST[cron_amazon_awsSecretKey] . '\';' . "\n";
254
 
255
+ $cfg .= '$_CONFIG[\'cron_amazon_bucket\']=\'' . $_REQUEST[cron_amazon_bucket] . '\';' . "\n";
256
 
257
+ $cfg .= '$_CONFIG[\'cron_amazon_dirname\']=\'' . $_REQUEST[cron_amazon_dirname] . '\';' . "\n";
258
+
259
+ $cfg .= '$_CONFIG[\'cron_amazon_ssl\']=\'' . $_REQUEST[cron_amazon_ssl] . '\';' . "\n";
260
+
261
+ $cfg .= '$_CONFIG[\'cron_dropbox_active\']=\'' . $_REQUEST[cron_dropbox_active] . '\';' . "\n";
262
+
263
+ $cfg .= '$_CONFIG[\'cron_dropbox_Key\']=\'' . $_REQUEST[cron_dropbox_Key] . '\';' . "\n";
264
+
265
+ $cfg .= '$_CONFIG[\'cron_dropbox_Secret\']=\'' . $_REQUEST[cron_dropbox_Secret] . '\';' . "\n";
266
+
267
+ $cfg .= '$_CONFIG[\'cron_dropbox_dirname\']=\'' . $_REQUEST[cron_dropbox_dirname] . '\';' . "\n";
268
 
269
  $cfg .= '$_CONFIG[\'debug\']="' . $_REQUEST[debug] . '";' . "\n";
270
 
287
  } else {
288
 
289
 
290
+ $msg = "Unable to save ".$fcron." file, please make sure the folder is writeable!";
291
  }
292
  }
293
 
299
  E_print($msg);
300
  }
301
  }
302
+ $html = new HTML_cloner();
303
+ $html->Config($option);
304
  }
305
 
306
  //## JoomlaCloner Language Manager
326
  mosRedirect('index2.php?option=' . $option . "&task=lang", $msg);
327
  }
328
 
329
+ $html = new HTML_cloner();
330
+ $html->Translator($option, $lang_array);
331
  }
332
 
333
  function translator_add($option, $task)
353
 
354
  mosRedirect('index2.php?option=' . $option . "&task=lang", $msg);
355
  }
356
+
357
+ $html = new HTML_cloner();
358
+ $html->Translator_Add($option);
359
  }
360
  function translator_edit($option, $task)
361
  {
437
 
438
 
439
  if ($lang == 'english') {
440
+ $html = new HTML_cloner();
441
+ $html->Translator_Edit_DEFAULT($option, $content, $file, $lang);
442
  } else {
443
  $def_data = get_lang_data($dfile);
444
  $cur_data = get_lang_data($file);
445
 
446
  $data = array_merge($def_data, $cur_data);
447
+ $html = new HTML_cloner();
448
+ $html->Translator_Edit($option, $data, $def_data, $file, $lang);
449
  }
450
  }
451
 
493
  return $lang_arr;
494
  }
495
 
496
+ function goRecurseDatabases(){
497
+ global $_CONFIG;
498
+
499
+ include_once("classes/mysqlBackup.class.php");
500
+
501
+ $return = array();
502
+
503
+ $data['dbHostname'] = $_CONFIG['mysql_host'];
504
+ $data['dbUsername'] = $_CONFIG['mysql_user'];
505
+ $data['dbPassword'] = $_CONFIG['mysql_pass'];
506
+ $data['dbDatabase'] = $_CONFIG['mysql_database'];
507
+ $data['excludedTables'] = "";
508
+ $data['recordsPerSession'] = $_CONFIG['recordsPerSession'];
509
+ $data['dbCompatibility'] = $_REQUEST['dbbackup_comp']; //version compatibility
510
+ $data['dbDropSyntax'] = $_REQUEST['dbbackup_drop']; //Add DROP Syntax
511
+
512
+ $data['TEMP_DUMP_FILE'] = $_CONFIG['temp_dir']."/database-sql.sql";
513
+ $data['TEMP_DBPROCESS_FILE'] = $_CONFIG['temp_dir']."/.database";
514
+
515
+ if($_REQUEST['mode'] == "start"){
516
+ //do the initial table readings
517
+
518
+ //foreach($_REQUEST['excltables'] as $value) //check if any tables are excluded, we will only export their structure
519
+ $data['excludedTables'] = $_REQUEST['excltables'];
520
+
521
+ //foreach($_REQUEST['excltables'] as $value) //check if any other databases are included
522
+ $extradb = $_REQUEST['databases_incl'];
523
+
524
+ $db = new DB();
525
+ $db->init($data, 1);
526
+ $db->writeTempFile();
527
+ $db->disconnect();
528
+
529
+ //building the .database temp file
530
+ if(is_array($extradb))
531
+ foreach($extradb as $database){
532
+ $data['dbDatabase'] = $database;
533
+ $data['TEMP_DUMP_FILE'] = $_CONFIG['temp_dir']."/".$data['dbDatabase']."-sql.sql";
534
+ $db = new DB();
535
+ $db->init($data);
536
+ $db->writeTempFile();
537
+ $db->disconnect();
538
+
539
+ }
540
+
541
+ return;
542
+ }
543
+
544
+ //we start the backup process for the actual database
545
+
546
+ $data['dbDatabase'] = "";
547
+ $dumpfile = "";
548
+ $data['dbCompatibility'] = $_REQUEST['dbbackup_comp']; //version compatibility
549
+ $data['dbDropSyntax'] = $_REQUEST['dbbackup_drop']; //Add DROP Syntax
550
+ $startAtLine = intval($_REQUEST['startAtLine']);
551
+ $startAtRecord = intval($_REQUEST['startAtRecord']);
552
+ $dumpfile = $_REQUEST['dumpfile'];
553
+
554
+ $db = new DB();
555
+ $db->init($data);
556
+
557
+ $records = $db->resetcountRecords();
558
+
559
+ while(($records < $_CONFIG['recordsPerSession']) and (!$return['finished']) and(!$return['newDump']) and(!$return['endDump'])){
560
+
561
+ $return = $db->processIncremental($startAtLine, $startAtRecord, $dumpfile);
562
+
563
+ $records = $db->getcountRecords();
564
+ $startAtLine = $return['startAtLine'];
565
+ $startAtRecord = $return['startAtRecord'];
566
+ $dumpfile = $return['dumpfile'];
567
+
568
+ }
569
+
570
+ /*if($return['newDump'])
571
+ print_r($return);*/
572
+ /*$startAtLine = $return['startAtLine'];
573
+ $startAtRecord = $return['startAtRecord'];
574
+ $dumpfile = $return['dumpfile'];*/
575
+
576
+ $return['dbbackup_comp'] = $_REQUEST['dbbackup_comp'];
577
+ $return['dbbackup_drop'] = $_REQUEST['dbbackup_drop'];
578
+
579
+ if($return['databaseName'] == "###enddump###")
580
+ $return['databaseName'] = "";
581
+
582
+ $db->disconnect();
583
+
584
+ echo json_encode($return);
585
+ exit;
586
+
587
+ }
588
 
589
  function goRecurseFiles(){
590
 
591
  global $_CONFIG;
592
+
593
  include_once("classes/fileRecursion.php");
594
 
595
  $status['finished'] = "1";
597
 
598
  $handle = new fileRecursion();
599
 
600
+ $dataInit['TEMP_PERM'] = $_CONFIG['temp_dir']."/perm.txt";
601
+ $dataInit['TEMP_EXCL'] = $_CONFIG['exfile'];
602
+ $dataInit['TEMP_D_ARR'] = $_CONFIG['temp_dir']."/.dir";
603
+ $dataInit['TEMP_DIR'] = $_CONFIG['clonerPath'];
604
+ $dataInit['START_DIR'] = $_CONFIG['backup_path'];
605
+ $dataInit['EXCLUDE_FILES_SIZE'] = $_CONFIG['excludeFilesSize'];
606
+ $dataInit['TEMP_OVERSIZED_FILE'] = $_CONFIG['temp_dir']."/.oversized_files";
607
 
608
+ $handle->setData($dataInit);
609
 
610
  if($_REQUEST['mode'] == 'start')
611
+ $handle->init($_CONFIG['backup_start_path']);
612
  else
613
  $handle->init();
614
 
623
 
624
  if(!$handle->isQueueFinished())
625
  $status['finished'] = "0";
626
+ else{
627
+ //recurse finished, lets return the excluded files by size
628
+ if(intval($_CONFIG['EXCLUDE_FILES_SIZE']) > -1){
629
+ $status['overlimit'] = $handle->getOverLimitFiles();
630
+ }
631
+ }
632
 
633
  echo json_encode($status);
634
+ $handle->close();
635
  exit;
636
 
637
  }
660
  getBackupFiles($d_arr, $f_arr, $s_arr, $d, $f);
661
 
662
  // load presentation layer
663
+ $html = new HTML_cloner();
664
+ $html->showBackups($f_arr, $s_arr, $_CONFIG['clonerPath'], $option);
665
  }
666
 
667
  function moveBackup($option)
677
  if ($_REQUEST['action'] == "connect") {
678
  $ret = start_connect($_REQUEST[files]);
679
  }
680
+ if (!$ret){
681
+ $html = new HTML_cloner();
682
+ $html->TransferForm($option, $files_out);
683
+ }
684
  }
685
 
686
  function start_connect($files)
912
  }
913
 
914
 
915
+ $html = new HTML_cloner();
916
+ $html->rename($files, $option);
917
  }
918
  function downloadBackup($file)
919
  {
920
  global $_CONFIG;
921
 
922
+ $file = realpath($_CONFIG['clonerPath'] . "/$file");
923
 
924
  //First, see if the file exists
925
  if (!is_file($file)) {
933
 
934
  //Setam Content-Type-urile pentru fisierul in cauza
935
  switch ($file_extension) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
936
  default:
937
  $ctype = "application/force-download";
938
  }
939
 
940
+ smartReadFile($file, $filename);
 
 
 
 
 
 
 
 
941
 
 
 
 
 
 
 
942
  exit;
943
  }
944
 
945
+ function smartReadFile($location, $filename, $mimeType='application/octet-stream')
946
+ { if(!file_exists($location))
947
+ { header ("HTTP/1.0 404 Not Found");
948
+ return;
949
+ }
950
+
951
+ $size=filesize($location);
952
+ $time=date('r',filemtime($location));
953
+
954
+ $fm=@fopen($location,'r');
955
+ if(!$fm)
956
+ { header ("HTTP/1.0 505 Internal server error");
957
+ return;
958
+ }
959
+
960
+ $begin=0;
961
+ $end=$size;
962
+
963
+ if(isset($_SERVER['HTTP_RANGE']))
964
+ { if(preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches))
965
+ { $begin=intval($matches[0]);
966
+ if(!empty($matches[1]))
967
+ $end=intval($matches[1]);
968
+ }
969
+ }
970
+
971
+ if($begin>0||$end<$size)
972
+ header('HTTP/1.0 206 Partial Content');
973
+ else
974
+ header('HTTP/1.0 200 OK');
975
+
976
+ header("Content-Type: $mimeType");
977
+ header('Cache-Control: public, must-revalidate, max-age=0');
978
+ header('Pragma: no-cache');
979
+ header('Accept-Ranges: bytes');
980
+ header('Content-Length:'.($end-$begin));
981
+ header("Content-Range: bytes $begin-$end/$size");
982
+ header("Content-Disposition: inline; filename=$filename");
983
+ header("Content-Transfer-Encoding: binary\n");
984
+ header("Last-Modified: $time");
985
+ header('Connection: close');
986
+
987
+ $cur=$begin;
988
+ fseek($fm,$begin,0);
989
+
990
+ while(!feof($fm)&&$cur<$end&&(connection_status()==0))
991
+ { print fread($fm,min(1024*16,$end-$cur));
992
+ $cur+=1024*16;
993
+ }
994
+ }
995
+
996
 
997
  function confirmBackup($option)
998
  {
1042
  }
1043
 
1044
  // load presentation layer
1045
+ if ($option != 'nohtml'){
1046
+ $html = new HTML_cloner();
1047
+ $html->confirmBackups($d_arr, $ds_arr, $_CONFIG['clonerPath'], $option);
1048
+ }else
1049
  return $d_arr;
1050
  }
1051
 
1083
 
1084
  $log = "";
1085
 
1086
+ $backup_file = $_CONFIG['backup_store_path']."/".$backup_filename;
1087
 
1088
+ $perm_file = $_CONFIG['temp_dir'] . "/perm.txt";
1089
 
1090
 
1091
  $lines = $_REQUEST['lines'];
1109
 
1110
  $url = "index2.php?option=com_cloner&task=refresh&json=$json&startf=$endf&lines=$lines&backup=$backup_filename&excl_manual=" . $_REQUEST['excl_manual'];
1111
 
 
1112
  if ($endf >= $lines)
1113
  $endf = $lines;
1114
  else
1117
  if ((int)$lines != 0)
1118
  $percent = sprintf("%d", ($endf * 100) / (int)$lines);
1119
 
 
1120
  $log .= "Total process: $percent% out of $lines files<br />\n";
1121
  $log .= "Processing files $startf to $endf for backup file $backup_file!<br />\n";
1122
  $log .= "Current backup size: " . getFileSizeText(get_filesize($backup_file)) . "<br /><br />\n";
1129
 
1130
  $buffer = explode("|", fgets($fperm, 4096));
1131
 
1132
+ if (($line <= $endf) && ($line >= $startf)) {
1133
  $log .= "\n<br />$line. ";
1134
 
1135
  if (($buffer[0] != "") && (is_file($buffer[0]))) {
1138
  //## appending files
1139
  $log .= "file - $file";
1140
 
1141
+ if(intval($_CONFIG['splitBackupSize']) > 0){
1142
+
1143
+ $fileSize = intval($buffer[2]);
1144
+ $backupSize = get_filesize($backup_file);
1145
+ $limit = $_CONFIG['splitBackupSize']*1024*1024; //MB limit
1146
+
1147
+ //check if the size is bigger than $_CONFIF['splitBackupSize'] and split backup
1148
+ if(($fileSize+$backupSize) > $limit){
1149
+
1150
+ $backup_filename = getNewBackupName($backup_filename);
1151
+ //exit;
1152
+ $backup_file = $_CONFIG['backup_store_path']."/".$backup_filename;
1153
+
1154
+ }
1155
+
1156
+ }
1157
+
1158
 
1159
  if (!$_CONFIG['mem']) {
1160
  //### CREATE BACKUP USING TAR LIBRARIES
1188
  }
1189
 
1190
  //exit;
1191
+ $newFileSize = get_filesize($backup_file);
1192
  $log .= "\n<br />New backup size: " . $newFileSize . "<br />\n";
1193
 
1194
  addXLog($log);
1203
  //# REDIRECTING
1204
  @fclose($fperm);
1205
 
1206
+ $log .= "<br>All done, redirecting... or <a href='$url'>click here </a>";
1207
 
1208
  $log .= "
1209
+ <script language='javascript'>
1210
+ function redirect(){
1211
+ window.location = '" . $url . "';
1212
+ }
1213
 
1214
+ setTimeout(\"redirect()\",parseInt(" . $_CONFIG['refresh_time'] . "));
1215
+ //redirect();
1216
 
1217
+ </script>";
1218
  }
 
 
1219
 
1220
+ } else {
1221
  $log .= "Unable to continue, could not open file $perm_file for reading!";
1222
  }
1223
 
1231
  $status['finished'] = 1;
1232
  }
1233
 
1234
+ if(!$json){
1235
+ echo $log;
1236
  }
1237
+ else{
1238
  $status['backupSize'] = $newFileSize;
1239
  $status['percent'] = $percent;
1240
  $status['option'] = 'com_cloner';
1248
  echo json_encode($status);
1249
  exit;
1250
 
1251
+ }
1252
 
1253
  return;
1254
  }
1267
  if (!$_CONFIG['enable_db_backup']) {
1268
  $backupDatabase = 0;
1269
  } else {
1270
+ $backupDatabase = $_REQUEST['dbbackup'];
 
 
1271
  }
1272
 
1273
  if ($_REQUEST[cron_access]) {
1304
  $f_ext = '.tgz';
1305
  $_CONFIG['tarcompress'] = 'z';
1306
  } else {
 
 
1307
  $f_ext = '.tar';
1308
  $_CONFIG['tarcompress'] = '';
1309
  }
1333
  $filename1 = $_REQUEST['bname'] . $f_ext;
1334
  }
1335
 
1336
+ //check if comments are set
1337
+ if($_REQUEST['backupComments'] != "")
1338
+ writeComments($_REQUEST['backupComments']);
1339
+
1340
+ //we created the backup name, but skip sql at this step, we will do it incrementally
1341
+ if(($_CONFIG['refresh_mode']) and (!$_REQUEST[cron_access]))
1342
+ //we skip the backup at this process,we will do it incrementally
1343
+ $backupDatabase = 0;
1344
+
1345
  $sql_file = array();
1346
 
1347
  if ($backupDatabase == 1) {
1369
  mysql_query("USE " . $_CONFIG['mysql_database']);
1370
  }
1371
  } else {
1372
+ #$databaseResult = LM_DATABASE_EXCLUDED;
1373
  }
1374
 
1375
 
1462
 
1463
  if(($_REQUEST['cron_access']) or (!$_CONFIG['refresh_mode'])){
1464
 
1465
+ $perm_file = $_CONFIG['backups_dir'] . "/perm.txt";
1466
+ @unlink($perm_file);
1467
+ $fperm = fopen($perm_file, "w");
1468
 
1469
+ for ($i = 0; $i < sizeof($excluded); $i++) {
1470
+ $excluded[$i] = str_replace("//", "/", $excluded[$i]);
1471
+ }
1472
 
1473
+ // obtain the list of files by recursing the mambo file store
1474
+ addXLog("Starting the file scanning process");
1475
 
1476
+ recurseFiles($d_arr, $ds_arr, $f_arr, $s_arr, $d, $f, $s, $includeFolder, '', $excluded, $fperm);
 
 
1477
 
1478
+ @fclose($fperm);
1479
+
1480
+ @chmod($perm_file, 0777);
1481
+
1482
+ }
1483
 
1484
 
1485
  // format total archive size
1535
 
1536
  if ($_CONFIG['backup_refresh']) {
1537
  $f_arr = array($_CONFIG['backups_dir'] . "/index.html");
1538
+ $fp=@fopen($_CONFIG['backups_dir'] . "/index.html" , "w");
1539
+ if($fp)
1540
+ fclose($fp);
1541
  }
1542
 
1543
 
1560
 
1561
  if ($_CONFIG['backup_refresh']) {
1562
  // echo "Starting the manual backup process!<br />";
1563
+ if((!$_CONFIG['refresh_mode']) and ($_CONFIG['enable_db_backup']))
1564
+ echo "<h2>Database backup: </h2>" . $databaseResult . "<br /><br />";
1565
+ $html = new HTML_cloner();
1566
+ $html->goRefreshHtml($filename, $perm_lines, $excl_manual);
1567
  return;
1568
  }
1569
 
1655
  E_print("Backup failed, please check your tar server utility support!");
1656
  return;
1657
  }*/
1658
+ $html = new HTML_cloner();
1659
+ $html->goRefreshHtml($filename, $perm_lines, $excl_manual);
1660
 
1661
  return;
1662
  }
1698
 
1699
  // load presentation layer
1700
  if ($option != 'nohtml') {
1701
+ $html = new HTML_cloner();
1702
+ $html->generateBackup($filename1, $archiveSize, $originalSize, $mdir, $f, $databaseResult, $option);
1703
  } else {
1704
 
1705
+ $html = new HTML_cloner();
1706
+ logxx($html->generateBackup_text($filename1, $archiveSize, $originalSize, $mdir, $f, $databaseResult, $option));
1707
  }
1708
 
1709
  if (is_array($databases_incl)) {
1727
  // ----------------------------------------------------------
1728
 
1729
  // load presentation layer
1730
+ $html = new HTML_cloner();
1731
+ $html->showHelp($option);
1732
  }
1733
 
1734
 
2071
  $InsertDump = "INSERT INTO `$tblval` VALUES (";
2072
  $arr = $row;
2073
  foreach ($arr as $key => $value) {
2074
+ $value = mysql_real_escape_string($value);
2075
+ #$value = str_replace("\n", '\r\n', $value);
2076
+ #$value = str_replace("\r", '', $value);
2077
  //if (@preg_match ("/\b" . $FieldType[$tblval][$key] . "\b/i", "DATE TIME DATETIME CHAR VARCHAR TEXT TINYTEXT MEDIUMTEXT LONGTEXT BLOB TINYBLOB MEDIUMBLOB LONGBLOB ENUM SET"))
2078
  {
2079
  $InsertDump .= "'$value',";
2102
  }
2103
  }
2104
 
2105
+ function getNewBackupName($backupFilename){
2106
 
2107
+ $newFilename = $backupFilename;
2108
+
2109
+ $tmp = explode(".",$backupFilename);
2110
+ $extension = $tmp[sizeof($tmp)-1];
2111
+ $inc = $tmp[sizeof($tmp)-2];
2112
+
2113
+ if(strlen($inc)<3){
2114
+ $newinc = $inc+1;
2115
+ $newFilename = str_replace(".$inc.$extension", "", $backupFilename); //ex, replace .1.tar
2116
+ $newFilename = $newFilename .".$newinc.$extension";
2117
+ }else{
2118
+ //it is a first backup, no .0.tar
2119
+ $newFilename = str_replace(".".$extension, "", $backupFilename); //ex, replace .1.tar
2120
+ $newFilename = $newFilename .".1.". $extension;
2121
+ }
2122
+
2123
+ return $newFilename;
2124
+ }
2125
+
2126
+ function writeComments($comments){
2127
+ global $_CONFIG;
2128
+
2129
+ $fp = @fopen($_CONFIG['commentsfile'], "w");
2130
+ if($fp){
2131
+ fwrite($fp, stripcslashes($comments));
2132
+ fclose($fp);
2133
+ }
2134
+ else{
2135
+ addXLog("Unable to write comments to file ".$_CONFIG['commentsfile']);
2136
+ }
2137
+
2138
+
2139
+ }
2140
+
2141
+ function getVersion()
2142
+ {
2143
+ $query = mysql_query("SELECT version()");
2144
+ $row = mysql_fetch_array($query);
2145
+ return $row[0];
2146
+ }
2147
  ?>
common.php CHANGED
@@ -1,31 +1,56 @@
1
  <?php
2
- /**
3
- * XCloner
4
- * Oficial website: http://www.joomlaplug.com/
5
- * -------------------------------------------
6
- * Creator: Liuta Romulus Ovidiu
7
- * License: All Rights Reserved
8
- * Email: admin@joomlaplug.com
9
- * Revision: 1.0
10
- * Date: July 2007
11
- **/
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  if ((!extension_loaded('zlib')) &&(function_exists('ob_start'))) {
13
  ob_end_clean();
14
  ob_start('ob_gzhandler');
15
- }
16
 
17
  ####################################
18
 
19
  $_CONFIG['multiple_config_dir'] = "configs";
 
 
 
 
 
 
20
 
21
- $_CONFIG['backup_path'] = realpath($_CONFIG['backup_path'])."/";
22
- $_CONFIG['backups_dir'] = realpath($_CONFIG['backup_path'])."/administrator/backups";
23
 
24
  $_CONFIG['backup_path'] = str_replace("\\","/", $_CONFIG['backup_path']);
25
  $_CONFIG['backups_dir'] = str_replace("\\","/", $_CONFIG['backups_dir']);
26
 
 
27
  $_CONFIG['exfile'] = $_CONFIG['backups_dir']."/.excl";
28
  $_CONFIG['exfile_tar'] = $_CONFIG['backups_dir']."/.excl_tar";
 
 
 
 
29
  $_CONFIG['script_path'] = str_replace("\\","/",dirname(__FILE__));
30
 
31
  $lang_dir = "language";
@@ -37,7 +62,7 @@ $task = $_REQUEST['task'];
37
  if($_CONFIG['enable_db_backup']){
38
 
39
  ### Connecting to the mysql server
40
- @mysql_connect($_CONFIG['mysql_host'], $_CONFIG['mysql_user'], $_CONFIG['mysql_pass']) or
41
  E_print("Could not connect: " . mysql_error());
42
  @mysql_select_db($_CONFIG['mysql_database']) or E_print("Unable to select database ".$_CONFIG['mysql_database']);
43
  @mysql_query("SET NAMES 'utf8'");
@@ -55,17 +80,20 @@ if (file_exists( "language/".$mosConfig_lang.".php" )) {
55
 
56
  @include_once( "language/english.php" );
57
 
58
- }
59
 
60
  else{
 
61
  include_once( "language/english.php" );
 
62
  }
63
 
64
  $version = str_replace(".", "", phpversion());
65
- if($version < 520){
66
  $_CONFIG['refresh_mode']="0";
67
  }
68
- if($_CONFIG['backup_refresh'] == "0"){
 
69
  $_CONFIG['refresh_mode']="0";
70
  }
71
 
@@ -73,4 +101,6 @@ $_CONFIG['backup_start_path'] = $_CONFIG['backup_path'];
73
  $_CONFIG['backup_store_path'] = $_CONFIG['clonerPath'];
74
  $_CONFIG['temp_dir'] = $_CONFIG['backups_dir'];
75
 
 
 
76
  ?>
1
  <?php
2
+ /*
3
+ * common.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
9
+ * the Free Software Foundation; either version 2 of the License, or
10
+ * (at your option) any later version.
11
+ *
12
+ * This program is distributed in the hope that it will be useful,
13
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
+ * GNU General Public License for more details.
16
+ *
17
+ * You should have received a copy of the GNU General Public License
18
+ * along with this program; if not, write to the Free Software
19
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ * MA 02110-1301, USA.
21
+ */
22
+
23
+ /** ensure this file is being included by a parent file */
24
+ defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
25
+
26
  if ((!extension_loaded('zlib')) &&(function_exists('ob_start'))) {
27
  ob_end_clean();
28
  ob_start('ob_gzhandler');
29
+ }
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'] = ($_CONFIG['backup_path']);
42
+ $_CONFIG['backups_dir'] = str_replace("//administrator","/administrator",($_CONFIG['backup_path'])."/administrator/backups");
43
 
44
  $_CONFIG['backup_path'] = str_replace("\\","/", $_CONFIG['backup_path']);
45
  $_CONFIG['backups_dir'] = str_replace("\\","/", $_CONFIG['backups_dir']);
46
 
47
+
48
  $_CONFIG['exfile'] = $_CONFIG['backups_dir']."/.excl";
49
  $_CONFIG['exfile_tar'] = $_CONFIG['backups_dir']."/.excl_tar";
50
+
51
+ $_CONFIG['logfile'] = $_CONFIG['backups_dir']."/xcloner.log";
52
+ $_CONFIG['commentsfile'] = $_CONFIG['backups_dir']."/.comments"; #$_REQUEST['backupComments']
53
+
54
  $_CONFIG['script_path'] = str_replace("\\","/",dirname(__FILE__));
55
 
56
  $lang_dir = "language";
62
  if($_CONFIG['enable_db_backup']){
63
 
64
  ### Connecting to the mysql server
65
+ $link = @mysql_connect($_CONFIG['mysql_host'], $_CONFIG['mysql_user'], $_CONFIG['mysql_pass']) or
66
  E_print("Could not connect: " . mysql_error());
67
  @mysql_select_db($_CONFIG['mysql_database']) or E_print("Unable to select database ".$_CONFIG['mysql_database']);
68
  @mysql_query("SET NAMES 'utf8'");
80
 
81
  @include_once( "language/english.php" );
82
 
83
+ }
84
 
85
  else{
86
+
87
  include_once( "language/english.php" );
88
+
89
  }
90
 
91
  $version = str_replace(".", "", phpversion());
92
+ if (version_compare(PHP_VERSION, '5.2.3') < 0) {
93
  $_CONFIG['refresh_mode']="0";
94
  }
95
+
96
+ if (!$_CONFIG['backup_refresh']) {
97
  $_CONFIG['refresh_mode']="0";
98
  }
99
 
101
  $_CONFIG['backup_store_path'] = $_CONFIG['clonerPath'];
102
  $_CONFIG['temp_dir'] = $_CONFIG['backups_dir'];
103
 
104
+ if(!ini_get('date.timezone'))
105
+ date_default_timezone_set('America/Los_Angeles');
106
  ?>
css/main.css CHANGED
@@ -155,16 +155,16 @@ a.pagenav:active {
155
  }
156
  .inputbox {
157
  z-index: -3;
158
- font-size: 11px;
159
  }
160
  .text_area {
161
  border : 1px solid #ccc;
162
  z-index: -3;
163
- font-size: 11px;
164
  }
165
  input, textarea, select {
166
  z-index : -3;
167
- font-size: 11px;
168
  }
169
  .small {
170
  color : #FF9900;
@@ -190,7 +190,7 @@ table.menubar {
190
 
191
  }
192
  td {
193
- font-size: 11px;
194
  }
195
  /* header block */
196
  table.adminheading {
@@ -309,7 +309,8 @@ table.adminlist th {
309
  padding: 6px 4px 2px 4px;
310
  height: 25px;
311
  background-repeat: repeat;
312
- font-size: 11px;
 
313
  color: #000;
314
  }
315
  table.adminlist th.title {
@@ -378,7 +379,6 @@ table.adminform th {
378
  table.adminform td {
379
  padding: 3px;
380
  border: solid 1px #d5d5d5;
381
-
382
  text-align: left;
383
  }
384
  table.adminform td.editor {
@@ -720,4 +720,88 @@ display:block;
720
  .mtext {
721
  font-weight: bold;
722
  font-size: 16px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
723
  }
155
  }
156
  .inputbox {
157
  z-index: -3;
158
+ font-size: 12px;
159
  }
160
  .text_area {
161
  border : 1px solid #ccc;
162
  z-index: -3;
163
+ font-size: 12px;
164
  }
165
  input, textarea, select {
166
  z-index : -3;
167
+ font-size: 14px;
168
  }
169
  .small {
170
  color : #FF9900;
190
 
191
  }
192
  td {
193
+ font-size: 12px;
194
  }
195
  /* header block */
196
  table.adminheading {
309
  padding: 6px 4px 2px 4px;
310
  height: 25px;
311
  background-repeat: repeat;
312
+ font-size: 13px;
313
+ text-align: left;
314
  color: #000;
315
  }
316
  table.adminlist th.title {
379
  table.adminform td {
380
  padding: 3px;
381
  border: solid 1px #d5d5d5;
 
382
  text-align: left;
383
  }
384
  table.adminform td.editor {
720
  .mtext {
721
  font-weight: bold;
722
  font-size: 16px;
723
+ display:inline;
724
+ }
725
+
726
+ #configtabinside div h3{
727
+ padding: 15px 0 5px 0;
728
+ font-weight: bold;
729
+ }
730
+
731
+ .backup_name {
732
+ font-size:16px;
733
+ }
734
+
735
+ #mysqlProcess{
736
+
737
+ padding-left: 50px;
738
+ }
739
+
740
+ #mysqlBackup{
741
+ padding-bottom: 10px;
742
+ }
743
+
744
+ #recurseFiles{
745
+
746
+ padding-left: 50px;
747
+ }
748
+
749
+ .mainText a{
750
+ font-weight: bold;
751
+ }
752
+
753
+ .mainText li{
754
+ font-weight: bold;
755
+ padding: 5px 0 5px 0;
756
+ list-style: disc inside;
757
+ }
758
+
759
+ .mainText{
760
+ padding: 5px 10px 10px 10px;
761
+ width: auto;
762
+ border: 1px solid #2e90bd;
763
+ }
764
+
765
+ .mainText h2{
766
+ padding-bottom: 5px;
767
+ }
768
+
769
+ .header a{
770
+ color: #000;
771
+ }
772
+
773
+ .adminForm textarea, .adminForm input, .adminForm select, .mainText input{
774
+ color: #000;
775
+ background: #fefefe;
776
+ border: 1px outset #2e90bd;
777
+ margin-left: 1px;
778
+ font-family: Tahoma, Arial;
779
+ }
780
+
781
+ .adminForm a, .adminform a {
782
+ font-family: Tahoma, Arial;
783
+ font-weight: bold;
784
+ }
785
+
786
+ .loginForm table {
787
+ border: 1px dashed #2e90bd;
788
+ font-size:12px;
789
+ }
790
+ .loginForm input{
791
+ color: #000;
792
+ background: #fefefe;
793
+ border: 1px outset #2e90bd;
794
+ margin-left: 1px;
795
+ font-family: Tahoma, Arial;
796
+
797
+ }
798
+ .oversizedFile{
799
+ padding-left: 25px;
800
+ }
801
+
802
+ .sliderContainer{
803
+
804
+ display: inline;
805
+ margin-bottom: 15px;
806
+
807
  }
css/start/images/ui-bg_flat_55_999999_40x100.png ADDED
Binary file
css/start/images/ui-bg_flat_75_aaaaaa_40x100.png ADDED
Binary file
css/start/images/ui-bg_glass_45_0078ae_1x400.png ADDED
Binary file
css/start/images/ui-bg_glass_55_f8da4e_1x400.png ADDED
Binary file
css/start/images/ui-bg_glass_75_79c9ec_1x400.png ADDED
Binary file
css/start/images/ui-bg_gloss-wave_45_e14f1c_500x100.png ADDED
Binary file
css/start/images/ui-bg_gloss-wave_50_6eac2c_500x100.png ADDED
Binary file
css/start/images/ui-bg_gloss-wave_75_2191c0_500x100.png ADDED
Binary file
css/start/images/ui-bg_inset-hard_100_fcfdfd_1x100.png ADDED
Binary file
css/start/images/ui-icons_0078ae_256x240.png ADDED
Binary file
css/start/images/ui-icons_056b93_256x240.png ADDED
Binary file
css/start/images/ui-icons_d8e7f3_256x240.png ADDED
Binary file
css/start/images/ui-icons_e0fdff_256x240.png ADDED
Binary file
css/start/images/ui-icons_f5e175_256x240.png ADDED
Binary file
css/start/images/ui-icons_f7a50d_256x240.png ADDED
Binary file
css/start/images/ui-icons_fcd113_256x240.png ADDED
Binary file
css/{jquery-ui.css → start/jquery-ui-1.8.9.custom.css} RENAMED
@@ -1,7 +1,7 @@
1
  /*
2
- * jQuery UI CSS Framework 1.8.8
3
  *
4
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
5
  * Dual licensed under the MIT or GPL Version 2 licenses.
6
  * http://jquery.org/license
7
  *
@@ -39,323 +39,48 @@
39
 
40
  /* Overlays */
41
  .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
42
- /*
43
- * jQuery UI Accordion 1.8.8
44
- *
45
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
46
- * Dual licensed under the MIT or GPL Version 2 licenses.
47
- * http://jquery.org/license
48
- *
49
- * http://docs.jquery.com/UI/Accordion#theming
50
- */
51
- /* IE/Win - Fix animation bug - #4615 */
52
- .ui-accordion { width: 100%; }
53
- .ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
54
- .ui-accordion .ui-accordion-li-fix { display: inline; }
55
- .ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
56
- .ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
57
- .ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
58
- .ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
59
- .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
60
- .ui-accordion .ui-accordion-content-active { display: block; }/*
61
- * jQuery UI Autocomplete 1.8.8
62
- *
63
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
64
- * Dual licensed under the MIT or GPL Version 2 licenses.
65
- * http://jquery.org/license
66
- *
67
- * http://docs.jquery.com/UI/Autocomplete#theming
68
- */
69
- .ui-autocomplete { position: absolute; cursor: default; }
70
-
71
- /* workarounds */
72
- * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
73
-
74
- /*
75
- * jQuery UI Menu 1.8.8
76
- *
77
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
78
- * Dual licensed under the MIT or GPL Version 2 licenses.
79
- * http://jquery.org/license
80
- *
81
- * http://docs.jquery.com/UI/Menu#theming
82
- */
83
- .ui-menu {
84
- list-style:none;
85
- padding: 2px;
86
- margin: 0;
87
- display:block;
88
- float: left;
89
- }
90
- .ui-menu .ui-menu {
91
- margin-top: -3px;
92
- }
93
- .ui-menu .ui-menu-item {
94
- margin:0;
95
- padding: 0;
96
- zoom: 1;
97
- float: left;
98
- clear: left;
99
- width: 100%;
100
- }
101
- .ui-menu .ui-menu-item a {
102
- text-decoration:none;
103
- display:block;
104
- padding:.2em .4em;
105
- line-height:1.5;
106
- zoom:1;
107
- }
108
- .ui-menu .ui-menu-item a.ui-state-hover,
109
- .ui-menu .ui-menu-item a.ui-state-active {
110
- font-weight: normal;
111
- margin: -1px;
112
- }
113
- /*
114
- * jQuery UI Button 1.8.8
115
- *
116
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
117
- * Dual licensed under the MIT or GPL Version 2 licenses.
118
- * http://jquery.org/license
119
- *
120
- * http://docs.jquery.com/UI/Button#theming
121
- */
122
- .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
123
- .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
124
- button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
125
- .ui-button-icons-only { width: 3.4em; }
126
- button.ui-button-icons-only { width: 3.7em; }
127
-
128
- /*button text element */
129
- .ui-button .ui-button-text { display: block; line-height: 1.4; }
130
- .ui-button-text-only .ui-button-text { padding: .4em 1em; }
131
- .ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
132
- .ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
133
- .ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
134
- .ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
135
- /* no icon support for input elements, provide padding by default */
136
- input.ui-button { padding: .4em 1em; }
137
 
138
- /*button icon element(s) */
139
- .ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
140
- .ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
141
- .ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
142
- .ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
143
- .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
144
-
145
- /*button sets*/
146
- .ui-buttonset { margin-right: 7px; }
147
- .ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
148
 
149
- /* workarounds */
150
- button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
151
  /*
152
- * jQuery UI Datepicker 1.8.8
153
  *
154
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
155
- * Dual licensed under the MIT or GPL Version 2 licenses.
156
- * http://jquery.org/license
157
- *
158
- * http://docs.jquery.com/UI/Datepicker#theming
159
- */
160
- .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
161
- .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
162
- .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
163
- .ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
164
- .ui-datepicker .ui-datepicker-prev { left:2px; }
165
- .ui-datepicker .ui-datepicker-next { right:2px; }
166
- .ui-datepicker .ui-datepicker-prev-hover { left:1px; }
167
- .ui-datepicker .ui-datepicker-next-hover { right:1px; }
168
- .ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
169
- .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
170
- .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
171
- .ui-datepicker select.ui-datepicker-month-year {width: 100%;}
172
- .ui-datepicker select.ui-datepicker-month,
173
- .ui-datepicker select.ui-datepicker-year { width: 49%;}
174
- .ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
175
- .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
176
- .ui-datepicker td { border: 0; padding: 1px; }
177
- .ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
178
- .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
179
- .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
180
- .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
181
-
182
- /* with multiple calendars */
183
- .ui-datepicker.ui-datepicker-multi { width:auto; }
184
- .ui-datepicker-multi .ui-datepicker-group { float:left; }
185
- .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
186
- .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
187
- .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
188
- .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
189
- .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
190
- .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
191
- .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
192
- .ui-datepicker-row-break { clear:both; width:100%; }
193
-
194
- /* RTL support */
195
- .ui-datepicker-rtl { direction: rtl; }
196
- .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
197
- .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
198
- .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
199
- .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
200
- .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
201
- .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
202
- .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
203
- .ui-datepicker-rtl .ui-datepicker-group { float:right; }
204
- .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
205
- .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
206
-
207
- /* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
208
- .ui-datepicker-cover {
209
- display: none; /*sorry for IE5*/
210
- display/**/: block; /*sorry for IE5*/
211
- position: absolute; /*must have*/
212
- z-index: -1; /*must have*/
213
- filter: mask(); /*must have*/
214
- top: -4px; /*must have*/
215
- left: -4px; /*must have*/
216
- width: 200px; /*must have*/
217
- height: 200px; /*must have*/
218
- }/*
219
- * jQuery UI Dialog 1.8.8
220
- *
221
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
222
- * Dual licensed under the MIT or GPL Version 2 licenses.
223
- * http://jquery.org/license
224
- *
225
- * http://docs.jquery.com/UI/Dialog#theming
226
- */
227
- .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
228
- .ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
229
- .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
230
- .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
231
- .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
232
- .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
233
- .ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
234
- .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
235
- .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
236
- .ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
237
- .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
238
- .ui-draggable .ui-dialog-titlebar { cursor: move; }
239
- /*
240
- * jQuery UI Progressbar 1.8.8
241
- *
242
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
243
- * Dual licensed under the MIT or GPL Version 2 licenses.
244
- * http://jquery.org/license
245
- *
246
- * http://docs.jquery.com/UI/Progressbar#theming
247
- */
248
- .ui-progressbar { height:2em; text-align: left; }
249
- .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }/*
250
- * jQuery UI Resizable 1.8.8
251
- *
252
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
253
- * Dual licensed under the MIT or GPL Version 2 licenses.
254
- * http://jquery.org/license
255
- *
256
- * http://docs.jquery.com/UI/Resizable#theming
257
- */
258
- .ui-resizable { position: relative;}
259
- .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
260
- .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
261
- .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
262
- .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
263
- .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
264
- .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
265
- .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
266
- .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
267
- .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
268
- .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
269
- * jQuery UI Selectable 1.8.8
270
- *
271
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
272
- * Dual licensed under the MIT or GPL Version 2 licenses.
273
- * http://jquery.org/license
274
- *
275
- * http://docs.jquery.com/UI/Selectable#theming
276
- */
277
- .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
278
- /*
279
- * jQuery UI Slider 1.8.8
280
- *
281
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
282
- * Dual licensed under the MIT or GPL Version 2 licenses.
283
- * http://jquery.org/license
284
- *
285
- * http://docs.jquery.com/UI/Slider#theming
286
- */
287
- .ui-slider { position: relative; text-align: left; }
288
- .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
289
- .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
290
-
291
- .ui-slider-horizontal { height: .8em; }
292
- .ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
293
- .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
294
- .ui-slider-horizontal .ui-slider-range-min { left: 0; }
295
- .ui-slider-horizontal .ui-slider-range-max { right: 0; }
296
-
297
- .ui-slider-vertical { width: .8em; height: 100px; }
298
- .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
299
- .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
300
- .ui-slider-vertical .ui-slider-range-min { bottom: 0; }
301
- .ui-slider-vertical .ui-slider-range-max { top: 0; }/*
302
- * jQuery UI Tabs 1.8.8
303
- *
304
- * Copyright 2010, 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/Tabs#theming
309
- */
310
- .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
311
- .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
312
- .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
313
- .ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
314
- .ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
315
- .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
316
- .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
317
- .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
318
- .ui-tabs .ui-tabs-hide { display: none !important; }
319
- /*
320
- * jQuery UI CSS Framework 1.8.8
321
- *
322
- * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
323
  * Dual licensed under the MIT or GPL Version 2 licenses.
324
  * http://jquery.org/license
325
  *
326
  * http://docs.jquery.com/UI/Theming/API
327
  *
328
- * To view and modify this theme, visit http://jqueryui.com/themeroller/
329
  */
330
 
331
 
332
  /* Component containers
333
  ----------------------------------*/
334
- .ui-widget { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1.1em/*{fsDefault}*/; }
335
  .ui-widget .ui-widget { font-size: 1em; }
336
- .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif/*{ffDefault}*/; font-size: 1em; }
337
- .ui-widget-content { border: 1px solid #aaaaaa/*{borderColorContent}*/; background: #ffffff/*{bgColorContent}*/ /*{bgImgUrlContent}*/ 50%/*{bgContentXPos}*/ 50%/*{bgContentYPos}*/ repeat-x/*{bgContentRepeat}*/; color: #222222/*{fcContent}*/; }
338
- .ui-widget-content a { color: #222222/*{fcContent}*/; }
339
- .ui-widget-header { border: 1px solid #aaaaaa/*{borderColorHeader}*/; background: #cccccc/*{bgColorHeader}*/ /*{bgImgUrlHeader}*/ 50%/*{bgHeaderXPos}*/ 50%/*{bgHeaderYPos}*/ repeat-x/*{bgHeaderRepeat}*/; color: #222222/*{fcHeader}*/; font-weight: bold; }
340
- .ui-widget-header a { color: #222222/*{fcHeader}*/; }
341
 
342
  /* Interaction states
343
  ----------------------------------*/
344
- .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #d3d3d3/*{borderColorDefault}*/; background: #e6e6e6/*{bgColorDefault}*/ url(images/ui-bg_glass_75_e6e6e6_1x400.png)/*{bgImgUrlDefault}*/ 50%/*{bgDefaultXPos}*/ 50%/*{bgDefaultYPos}*/ repeat-x/*{bgDefaultRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #555555/*{fcDefault}*/; }
345
- .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #555555/*{fcDefault}*/; text-decoration: none; }
346
- .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #999999/*{borderColorHover}*/; background: #dadada/*{bgColorHover}*/ url(images/ui-bg_glass_75_dadada_1x400.png)/*{bgImgUrlHover}*/ 50%/*{bgHoverXPos}*/ 50%/*{bgHoverYPos}*/ repeat-x/*{bgHoverRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcHover}*/; }
347
- .ui-state-hover a, .ui-state-hover a:hover { color: #212121/*{fcHover}*/; text-decoration: none; }
348
- .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #aaaaaa/*{borderColorActive}*/; background: #ffffff/*{bgColorActive}*/ url(images/ui-bg_glass_65_ffffff_1x400.png)/*{bgImgUrlActive}*/ 50%/*{bgActiveXPos}*/ 50%/*{bgActiveYPos}*/ repeat-x/*{bgActiveRepeat}*/; font-weight: normal/*{fwDefault}*/; color: #212121/*{fcActive}*/; }
349
- .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #212121/*{fcActive}*/; text-decoration: none; }
350
  .ui-widget :active { outline: none; }
351
 
352
  /* Interaction Cues
353
  ----------------------------------*/
354
- .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcefa1/*{borderColorHighlight}*/; background: #fbf9ee/*{bgColorHighlight}*/ url(images/ui-bg_glass_55_fbf9ee_1x400.png)/*{bgImgUrlHighlight}*/ 50%/*{bgHighlightXPos}*/ 50%/*{bgHighlightYPos}*/ repeat-x/*{bgHighlightRepeat}*/; color: #363636/*{fcHighlight}*/; }
355
- .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #363636/*{fcHighlight}*/; }
356
- .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a/*{borderColorError}*/; background: #fef1ec/*{bgColorError}*/ url(images/ui-bg_glass_95_fef1ec_1x400.png)/*{bgImgUrlError}*/ 50%/*{bgErrorXPos}*/ 50%/*{bgErrorYPos}*/ repeat-x/*{bgErrorRepeat}*/; color: #cd0a0a/*{fcError}*/; }
357
- .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #cd0a0a/*{fcError}*/; }
358
- .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #cd0a0a/*{fcError}*/; }
359
  .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
360
  .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
361
  .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
@@ -364,14 +89,14 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
364
  ----------------------------------*/
365
 
366
  /* states and images */
367
- .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
368
- .ui-widget-content .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsContent}*/; }
369
- .ui-widget-header .ui-icon {background-image: url(images/ui-icons_222222_256x240.png)/*{iconsHeader}*/; }
370
- .ui-state-default .ui-icon { background-image: url(images/ui-icons_888888_256x240.png)/*{iconsDefault}*/; }
371
- .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsHover}*/; }
372
- .ui-state-active .ui-icon {background-image: url(images/ui-icons_454545_256x240.png)/*{iconsActive}*/; }
373
- .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_2e83ff_256x240.png)/*{iconsHighlight}*/; }
374
- .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_cd0a0a_256x240.png)/*{iconsError}*/; }
375
 
376
  /* positioning */
377
  .ui-icon-carat-1-n { background-position: 0 0; }
@@ -555,16 +280,294 @@ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra pad
555
  ----------------------------------*/
556
 
557
  /* Corner radius */
558
- .ui-corner-tl { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; }
559
- .ui-corner-tr { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; }
560
- .ui-corner-bl { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; }
561
- .ui-corner-br { -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
562
- .ui-corner-top { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; }
563
- .ui-corner-bottom { -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
564
- .ui-corner-right { -moz-border-radius-topright: 4px/*{cornerRadius}*/; -webkit-border-top-right-radius: 4px/*{cornerRadius}*/; border-top-right-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomright: 4px/*{cornerRadius}*/; -webkit-border-bottom-right-radius: 4px/*{cornerRadius}*/; border-bottom-right-radius: 4px/*{cornerRadius}*/; }
565
- .ui-corner-left { -moz-border-radius-topleft: 4px/*{cornerRadius}*/; -webkit-border-top-left-radius: 4px/*{cornerRadius}*/; border-top-left-radius: 4px/*{cornerRadius}*/; -moz-border-radius-bottomleft: 4px/*{cornerRadius}*/; -webkit-border-bottom-left-radius: 4px/*{cornerRadius}*/; border-bottom-left-radius: 4px/*{cornerRadius}*/; }
566
- .ui-corner-all { -moz-border-radius: 4px/*{cornerRadius}*/; -webkit-border-radius: 4px/*{cornerRadius}*/; border-radius: 4px/*{cornerRadius}*/; }
567
 
568
  /* Overlays */
569
- .ui-widget-overlay { background: #aaaaaa/*{bgColorOverlay}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlOverlay}*/ 50%/*{bgOverlayXPos}*/ 50%/*{bgOverlayYPos}*/ repeat-x/*{bgOverlayRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityOverlay}*/; }
570
- .ui-widget-shadow { margin: -8px/*{offsetTopShadow}*/ 0 0 -8px/*{offsetLeftShadow}*/; padding: 8px/*{thicknessShadow}*/; background: #aaaaaa/*{bgColorShadow}*/ url(images/ui-bg_flat_0_aaaaaa_40x100.png)/*{bgImgUrlShadow}*/ 50%/*{bgShadowXPos}*/ 50%/*{bgShadowYPos}*/ repeat-x/*{bgShadowRepeat}*/; opacity: .3;filter:Alpha(Opacity=30)/*{opacityShadow}*/; -moz-border-radius: 8px/*{cornerRadiusShadow}*/; -webkit-border-radius: 8px/*{cornerRadiusShadow}*/; border-radius: 8px/*{cornerRadiusShadow}*/; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  /*
2
+ * jQuery UI CSS Framework 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
  *
39
 
40
  /* Overlays */
41
  .ui-widget-overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
42
 
 
 
 
 
 
 
 
 
 
 
43
 
 
 
44
  /*
45
+ * jQuery UI CSS Framework 1.8.9
46
  *
47
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
  * Dual licensed under the MIT or GPL Version 2 licenses.
49
  * http://jquery.org/license
50
  *
51
  * http://docs.jquery.com/UI/Theming/API
52
  *
53
+ * To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=5px&bgColorHeader=2191c0&bgTextureHeader=12_gloss_wave.png&bgImgOpacityHeader=75&borderColorHeader=4297d7&fcHeader=eaf5f7&iconColorHeader=d8e7f3&bgColorContent=fcfdfd&bgTextureContent=06_inset_hard.png&bgImgOpacityContent=100&borderColorContent=a6c9e2&fcContent=222222&iconColorContent=0078ae&bgColorDefault=0078ae&bgTextureDefault=02_glass.png&bgImgOpacityDefault=45&borderColorDefault=77d5f7&fcDefault=ffffff&iconColorDefault=e0fdff&bgColorHover=79c9ec&bgTextureHover=02_glass.png&bgImgOpacityHover=75&borderColorHover=448dae&fcHover=026890&iconColorHover=056b93&bgColorActive=6eac2c&bgTextureActive=12_gloss_wave.png&bgImgOpacityActive=50&borderColorActive=acdd4a&fcActive=ffffff&iconColorActive=f5e175&bgColorHighlight=f8da4e&bgTextureHighlight=02_glass.png&bgImgOpacityHighlight=55&borderColorHighlight=fcd113&fcHighlight=915608&iconColorHighlight=f7a50d&bgColorError=e14f1c&bgTextureError=12_gloss_wave.png&bgImgOpacityError=45&borderColorError=cd0a0a&fcError=ffffff&iconColorError=fcd113&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=75&opacityOverlay=30&bgColorShadow=999999&bgTextureShadow=01_flat.png&bgImgOpacityShadow=55&opacityShadow=45&thicknessShadow=0px&offsetTopShadow=5px&offsetLeftShadow=5px&cornerRadiusShadow=5px
54
  */
55
 
56
 
57
  /* Component containers
58
  ----------------------------------*/
59
+ .ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
60
  .ui-widget .ui-widget { font-size: 1em; }
61
+ .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
62
+ .ui-widget-content { border: 1px solid #a6c9e2; background: #fcfdfd url(images/ui-bg_inset-hard_100_fcfdfd_1x100.png) 50% bottom repeat-x; color: #222222; }
63
+ .ui-widget-content a { color: #222222; }
64
+ .ui-widget-header { border: 1px solid #4297d7; background: #2191c0 url(images/ui-bg_gloss-wave_75_2191c0_500x100.png) 50% 50% repeat-x; color: #eaf5f7; font-weight: bold; }
65
+ .ui-widget-header a { color: #eaf5f7; }
66
 
67
  /* Interaction states
68
  ----------------------------------*/
69
+ .ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default { border: 1px solid #77d5f7; background: #0078ae url(images/ui-bg_glass_45_0078ae_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #ffffff; }
70
+ .ui-state-default a, .ui-state-default a:link, .ui-state-default a:visited { color: #ffffff; text-decoration: none; }
71
+ .ui-state-hover, .ui-widget-content .ui-state-hover, .ui-widget-header .ui-state-hover, .ui-state-focus, .ui-widget-content .ui-state-focus, .ui-widget-header .ui-state-focus { border: 1px solid #448dae; background: #79c9ec url(images/ui-bg_glass_75_79c9ec_1x400.png) 50% 50% repeat-x; font-weight: normal; color: #026890; }
72
+ .ui-state-hover a, .ui-state-hover a:hover { color: #026890; text-decoration: none; }
73
+ .ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active { border: 1px solid #acdd4a; background: #6eac2c url(images/ui-bg_gloss-wave_50_6eac2c_500x100.png) 50% 50% repeat-x; font-weight: normal; color: #ffffff; }
74
+ .ui-state-active a, .ui-state-active a:link, .ui-state-active a:visited { color: #ffffff; text-decoration: none; }
75
  .ui-widget :active { outline: none; }
76
 
77
  /* Interaction Cues
78
  ----------------------------------*/
79
+ .ui-state-highlight, .ui-widget-content .ui-state-highlight, .ui-widget-header .ui-state-highlight {border: 1px solid #fcd113; background: #f8da4e url(images/ui-bg_glass_55_f8da4e_1x400.png) 50% 50% repeat-x; color: #915608; }
80
+ .ui-state-highlight a, .ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a { color: #915608; }
81
+ .ui-state-error, .ui-widget-content .ui-state-error, .ui-widget-header .ui-state-error {border: 1px solid #cd0a0a; background: #e14f1c url(images/ui-bg_gloss-wave_45_e14f1c_500x100.png) 50% top repeat-x; color: #ffffff; }
82
+ .ui-state-error a, .ui-widget-content .ui-state-error a, .ui-widget-header .ui-state-error a { color: #ffffff; }
83
+ .ui-state-error-text, .ui-widget-content .ui-state-error-text, .ui-widget-header .ui-state-error-text { color: #ffffff; }
84
  .ui-priority-primary, .ui-widget-content .ui-priority-primary, .ui-widget-header .ui-priority-primary { font-weight: bold; }
85
  .ui-priority-secondary, .ui-widget-content .ui-priority-secondary, .ui-widget-header .ui-priority-secondary { opacity: .7; filter:Alpha(Opacity=70); font-weight: normal; }
86
  .ui-state-disabled, .ui-widget-content .ui-state-disabled, .ui-widget-header .ui-state-disabled { opacity: .35; filter:Alpha(Opacity=35); background-image: none; }
89
  ----------------------------------*/
90
 
91
  /* states and images */
92
+ .ui-icon { width: 16px; height: 16px; background-image: url(images/ui-icons_0078ae_256x240.png); }
93
+ .ui-widget-content .ui-icon {background-image: url(images/ui-icons_0078ae_256x240.png); }
94
+ .ui-widget-header .ui-icon {background-image: url(images/ui-icons_d8e7f3_256x240.png); }
95
+ .ui-state-default .ui-icon { background-image: url(images/ui-icons_e0fdff_256x240.png); }
96
+ .ui-state-hover .ui-icon, .ui-state-focus .ui-icon {background-image: url(images/ui-icons_056b93_256x240.png); }
97
+ .ui-state-active .ui-icon {background-image: url(images/ui-icons_f5e175_256x240.png); }
98
+ .ui-state-highlight .ui-icon {background-image: url(images/ui-icons_f7a50d_256x240.png); }
99
+ .ui-state-error .ui-icon, .ui-state-error-text .ui-icon {background-image: url(images/ui-icons_fcd113_256x240.png); }
100
 
101
  /* positioning */
102
  .ui-icon-carat-1-n { background-position: 0 0; }
280
  ----------------------------------*/
281
 
282
  /* Corner radius */
283
+ .ui-corner-tl { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-top-left-radius: 5px; }
284
+ .ui-corner-tr { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; border-top-right-radius: 5px; }
285
+ .ui-corner-bl { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; }
286
+ .ui-corner-br { -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
287
+ .ui-corner-top { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-top-left-radius: 5px; -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; border-top-right-radius: 5px; }
288
+ .ui-corner-bottom { -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
289
+ .ui-corner-right { -moz-border-radius-topright: 5px; -webkit-border-top-right-radius: 5px; border-top-right-radius: 5px; -moz-border-radius-bottomright: 5px; -webkit-border-bottom-right-radius: 5px; border-bottom-right-radius: 5px; }
290
+ .ui-corner-left { -moz-border-radius-topleft: 5px; -webkit-border-top-left-radius: 5px; border-top-left-radius: 5px; -moz-border-radius-bottomleft: 5px; -webkit-border-bottom-left-radius: 5px; border-bottom-left-radius: 5px; }
291
+ .ui-corner-all { -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }
292
 
293
  /* Overlays */
294
+ .ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_75_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
295
+ .ui-widget-shadow { margin: 5px 0 0 5px; padding: 0px; background: #999999 url(images/ui-bg_flat_55_999999_40x100.png) 50% 50% repeat-x; opacity: .45;filter:Alpha(Opacity=45); -moz-border-radius: 5px; -webkit-border-radius: 5px; border-radius: 5px; }/*
296
+ * jQuery UI Resizable 1.8.9
297
+ *
298
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
299
+ * Dual licensed under the MIT or GPL Version 2 licenses.
300
+ * http://jquery.org/license
301
+ *
302
+ * http://docs.jquery.com/UI/Resizable#theming
303
+ */
304
+ .ui-resizable { position: relative;}
305
+ .ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
306
+ .ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
307
+ .ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
308
+ .ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
309
+ .ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
310
+ .ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
311
+ .ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
312
+ .ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
313
+ .ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
314
+ .ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
315
+ * jQuery UI Selectable 1.8.9
316
+ *
317
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
318
+ * Dual licensed under the MIT or GPL Version 2 licenses.
319
+ * http://jquery.org/license
320
+ *
321
+ * http://docs.jquery.com/UI/Selectable#theming
322
+ */
323
+ .ui-selectable-helper { position: absolute; z-index: 100; border:1px dotted black; }
324
+ /*
325
+ * jQuery UI Accordion 1.8.9
326
+ *
327
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
328
+ * Dual licensed under the MIT or GPL Version 2 licenses.
329
+ * http://jquery.org/license
330
+ *
331
+ * http://docs.jquery.com/UI/Accordion#theming
332
+ */
333
+ /* IE/Win - Fix animation bug - #4615 */
334
+ .ui-accordion { width: 100%; }
335
+ .ui-accordion .ui-accordion-header { cursor: pointer; position: relative; margin-top: 1px; zoom: 1; }
336
+ .ui-accordion .ui-accordion-li-fix { display: inline; }
337
+ .ui-accordion .ui-accordion-header-active { border-bottom: 0 !important; }
338
+ .ui-accordion .ui-accordion-header a { display: block; font-size: 1em; padding: .5em .5em .5em .7em; }
339
+ .ui-accordion-icons .ui-accordion-header a { padding-left: 2.2em; }
340
+ .ui-accordion .ui-accordion-header .ui-icon { position: absolute; left: .5em; top: 50%; margin-top: -8px; }
341
+ .ui-accordion .ui-accordion-content { padding: 1em 2.2em; border-top: 0; margin-top: -2px; position: relative; top: 1px; margin-bottom: 2px; overflow: auto; display: none; zoom: 1; }
342
+ .ui-accordion .ui-accordion-content-active { display: block; }
343
+ /*
344
+ * jQuery UI Autocomplete 1.8.9
345
+ *
346
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
347
+ * Dual licensed under the MIT or GPL Version 2 licenses.
348
+ * http://jquery.org/license
349
+ *
350
+ * http://docs.jquery.com/UI/Autocomplete#theming
351
+ */
352
+ .ui-autocomplete { position: absolute; cursor: default; }
353
+
354
+ /* workarounds */
355
+ * html .ui-autocomplete { width:1px; } /* without this, the menu expands to 100% in IE6 */
356
+
357
+ /*
358
+ * jQuery UI Menu 1.8.9
359
+ *
360
+ * Copyright 2010, 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/Menu#theming
365
+ */
366
+ .ui-menu {
367
+ list-style:none;
368
+ padding: 2px;
369
+ margin: 0;
370
+ display:block;
371
+ float: left;
372
+ }
373
+ .ui-menu .ui-menu {
374
+ margin-top: -3px;
375
+ }
376
+ .ui-menu .ui-menu-item {
377
+ margin:0;
378
+ padding: 0;
379
+ zoom: 1;
380
+ float: left;
381
+ clear: left;
382
+ width: 100%;
383
+ }
384
+ .ui-menu .ui-menu-item a {
385
+ text-decoration:none;
386
+ display:block;
387
+ padding:.2em .4em;
388
+ line-height:1.5;
389
+ zoom:1;
390
+ }
391
+ .ui-menu .ui-menu-item a.ui-state-hover,
392
+ .ui-menu .ui-menu-item a.ui-state-active {
393
+ font-weight: normal;
394
+ margin: -1px;
395
+ }
396
+ /*
397
+ * jQuery UI Button 1.8.9
398
+ *
399
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
400
+ * Dual licensed under the MIT or GPL Version 2 licenses.
401
+ * http://jquery.org/license
402
+ *
403
+ * http://docs.jquery.com/UI/Button#theming
404
+ */
405
+ .ui-button { display: inline-block; position: relative; padding: 0; margin-right: .1em; text-decoration: none !important; cursor: pointer; text-align: center; zoom: 1; overflow: visible; } /* the overflow property removes extra width in IE */
406
+ .ui-button-icon-only { width: 2.2em; } /* to make room for the icon, a width needs to be set here */
407
+ button.ui-button-icon-only { width: 2.4em; } /* button elements seem to need a little more width */
408
+ .ui-button-icons-only { width: 3.4em; }
409
+ button.ui-button-icons-only { width: 3.7em; }
410
+
411
+ /*button text element */
412
+ .ui-button .ui-button-text { display: block; line-height: 1.4; }
413
+ .ui-button-text-only .ui-button-text { padding: .4em 1em; }
414
+ .ui-button-icon-only .ui-button-text, .ui-button-icons-only .ui-button-text { padding: .4em; text-indent: -9999999px; }
415
+ .ui-button-text-icon-primary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 1em .4em 2.1em; }
416
+ .ui-button-text-icon-secondary .ui-button-text, .ui-button-text-icons .ui-button-text { padding: .4em 2.1em .4em 1em; }
417
+ .ui-button-text-icons .ui-button-text { padding-left: 2.1em; padding-right: 2.1em; }
418
+ /* no icon support for input elements, provide padding by default */
419
+ input.ui-button { padding: .4em 1em; }
420
+
421
+ /*button icon element(s) */
422
+ .ui-button-icon-only .ui-icon, .ui-button-text-icon-primary .ui-icon, .ui-button-text-icon-secondary .ui-icon, .ui-button-text-icons .ui-icon, .ui-button-icons-only .ui-icon { position: absolute; top: 50%; margin-top: -8px; }
423
+ .ui-button-icon-only .ui-icon { left: 50%; margin-left: -8px; }
424
+ .ui-button-text-icon-primary .ui-button-icon-primary, .ui-button-text-icons .ui-button-icon-primary, .ui-button-icons-only .ui-button-icon-primary { left: .5em; }
425
+ .ui-button-text-icon-secondary .ui-button-icon-secondary, .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
426
+ .ui-button-text-icons .ui-button-icon-secondary, .ui-button-icons-only .ui-button-icon-secondary { right: .5em; }
427
+
428
+ /*button sets*/
429
+ .ui-buttonset { margin-right: 7px; }
430
+ .ui-buttonset .ui-button { margin-left: 0; margin-right: -.3em; }
431
+
432
+ /* workarounds */
433
+ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
434
+ /*
435
+ * jQuery UI Dialog 1.8.9
436
+ *
437
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
438
+ * Dual licensed under the MIT or GPL Version 2 licenses.
439
+ * http://jquery.org/license
440
+ *
441
+ * http://docs.jquery.com/UI/Dialog#theming
442
+ */
443
+ .ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
444
+ .ui-dialog .ui-dialog-titlebar { padding: .4em 1em; position: relative; }
445
+ .ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .1em 0; }
446
+ .ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
447
+ .ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
448
+ .ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
449
+ .ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
450
+ .ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
451
+ .ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
452
+ .ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
453
+ .ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
454
+ .ui-draggable .ui-dialog-titlebar { cursor: move; }
455
+ /*
456
+ * jQuery UI Slider 1.8.9
457
+ *
458
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
459
+ * Dual licensed under the MIT or GPL Version 2 licenses.
460
+ * http://jquery.org/license
461
+ *
462
+ * http://docs.jquery.com/UI/Slider#theming
463
+ */
464
+ .ui-slider { position: relative; text-align: left; }
465
+ .ui-slider .ui-slider-handle { position: absolute; z-index: 2; width: 1.2em; height: 1.2em; cursor: default; }
466
+ .ui-slider .ui-slider-range { position: absolute; z-index: 1; font-size: .7em; display: block; border: 0; background-position: 0 0; }
467
+
468
+ .ui-slider-horizontal { height: .8em; }
469
+ .ui-slider-horizontal .ui-slider-handle { top: -.3em; margin-left: -.6em; }
470
+ .ui-slider-horizontal .ui-slider-range { top: 0; height: 100%; }
471
+ .ui-slider-horizontal .ui-slider-range-min { left: 0; }
472
+ .ui-slider-horizontal .ui-slider-range-max { right: 0; }
473
+
474
+ .ui-slider-vertical { width: .8em; height: 100px; }
475
+ .ui-slider-vertical .ui-slider-handle { left: -.3em; margin-left: 0; margin-bottom: -.6em; }
476
+ .ui-slider-vertical .ui-slider-range { left: 0; width: 100%; }
477
+ .ui-slider-vertical .ui-slider-range-min { bottom: 0; }
478
+ .ui-slider-vertical .ui-slider-range-max { top: 0; }/*
479
+ * jQuery UI Tabs 1.8.9
480
+ *
481
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
482
+ * Dual licensed under the MIT or GPL Version 2 licenses.
483
+ * http://jquery.org/license
484
+ *
485
+ * http://docs.jquery.com/UI/Tabs#theming
486
+ */
487
+ .ui-tabs { position: relative; padding: .2em; zoom: 1; } /* position: relative prevents IE scroll bug (element with position: relative inside container with overflow: auto appear as "fixed") */
488
+ .ui-tabs .ui-tabs-nav { margin: 0; padding: .2em .2em 0; }
489
+ .ui-tabs .ui-tabs-nav li { list-style: none; float: left; position: relative; top: 1px; margin: 0 .2em 1px 0; border-bottom: 0 !important; padding: 0; white-space: nowrap; }
490
+ .ui-tabs .ui-tabs-nav li a { float: left; padding: .5em 1em; text-decoration: none; }
491
+ .ui-tabs .ui-tabs-nav li.ui-tabs-selected { margin-bottom: 0; padding-bottom: 1px; }
492
+ .ui-tabs .ui-tabs-nav li.ui-tabs-selected a, .ui-tabs .ui-tabs-nav li.ui-state-disabled a, .ui-tabs .ui-tabs-nav li.ui-state-processing a { cursor: text; }
493
+ .ui-tabs .ui-tabs-nav li a, .ui-tabs.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-selected a { cursor: pointer; } /* first selector in group seems obsolete, but required to overcome bug in Opera applying cursor: text overall if defined elsewhere... */
494
+ .ui-tabs .ui-tabs-panel { display: block; border-width: 0; padding: 1em 1.4em; background: none; }
495
+ .ui-tabs .ui-tabs-hide { display: none !important; }
496
+ /*
497
+ * jQuery UI Datepicker 1.8.9
498
+ *
499
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
500
+ * Dual licensed under the MIT or GPL Version 2 licenses.
501
+ * http://jquery.org/license
502
+ *
503
+ * http://docs.jquery.com/UI/Datepicker#theming
504
+ */
505
+ .ui-datepicker { width: 17em; padding: .2em .2em 0; display: none; }
506
+ .ui-datepicker .ui-datepicker-header { position:relative; padding:.2em 0; }
507
+ .ui-datepicker .ui-datepicker-prev, .ui-datepicker .ui-datepicker-next { position:absolute; top: 2px; width: 1.8em; height: 1.8em; }
508
+ .ui-datepicker .ui-datepicker-prev-hover, .ui-datepicker .ui-datepicker-next-hover { top: 1px; }
509
+ .ui-datepicker .ui-datepicker-prev { left:2px; }
510
+ .ui-datepicker .ui-datepicker-next { right:2px; }
511
+ .ui-datepicker .ui-datepicker-prev-hover { left:1px; }
512
+ .ui-datepicker .ui-datepicker-next-hover { right:1px; }
513
+ .ui-datepicker .ui-datepicker-prev span, .ui-datepicker .ui-datepicker-next span { display: block; position: absolute; left: 50%; margin-left: -8px; top: 50%; margin-top: -8px; }
514
+ .ui-datepicker .ui-datepicker-title { margin: 0 2.3em; line-height: 1.8em; text-align: center; }
515
+ .ui-datepicker .ui-datepicker-title select { font-size:1em; margin:1px 0; }
516
+ .ui-datepicker select.ui-datepicker-month-year {width: 100%;}
517
+ .ui-datepicker select.ui-datepicker-month,
518
+ .ui-datepicker select.ui-datepicker-year { width: 49%;}
519
+ .ui-datepicker table {width: 100%; font-size: .9em; border-collapse: collapse; margin:0 0 .4em; }
520
+ .ui-datepicker th { padding: .7em .3em; text-align: center; font-weight: bold; border: 0; }
521
+ .ui-datepicker td { border: 0; padding: 1px; }
522
+ .ui-datepicker td span, .ui-datepicker td a { display: block; padding: .2em; text-align: right; text-decoration: none; }
523
+ .ui-datepicker .ui-datepicker-buttonpane { background-image: none; margin: .7em 0 0 0; padding:0 .2em; border-left: 0; border-right: 0; border-bottom: 0; }
524
+ .ui-datepicker .ui-datepicker-buttonpane button { float: right; margin: .5em .2em .4em; cursor: pointer; padding: .2em .6em .3em .6em; width:auto; overflow:visible; }
525
+ .ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current { float:left; }
526
+
527
+ /* with multiple calendars */
528
+ .ui-datepicker.ui-datepicker-multi { width:auto; }
529
+ .ui-datepicker-multi .ui-datepicker-group { float:left; }
530
+ .ui-datepicker-multi .ui-datepicker-group table { width:95%; margin:0 auto .4em; }
531
+ .ui-datepicker-multi-2 .ui-datepicker-group { width:50%; }
532
+ .ui-datepicker-multi-3 .ui-datepicker-group { width:33.3%; }
533
+ .ui-datepicker-multi-4 .ui-datepicker-group { width:25%; }
534
+ .ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header { border-left-width:0; }
535
+ .ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header { border-left-width:0; }
536
+ .ui-datepicker-multi .ui-datepicker-buttonpane { clear:left; }
537
+ .ui-datepicker-row-break { clear:both; width:100%; }
538
+
539
+ /* RTL support */
540
+ .ui-datepicker-rtl { direction: rtl; }
541
+ .ui-datepicker-rtl .ui-datepicker-prev { right: 2px; left: auto; }
542
+ .ui-datepicker-rtl .ui-datepicker-next { left: 2px; right: auto; }
543
+ .ui-datepicker-rtl .ui-datepicker-prev:hover { right: 1px; left: auto; }
544
+ .ui-datepicker-rtl .ui-datepicker-next:hover { left: 1px; right: auto; }
545
+ .ui-datepicker-rtl .ui-datepicker-buttonpane { clear:right; }
546
+ .ui-datepicker-rtl .ui-datepicker-buttonpane button { float: left; }
547
+ .ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current { float:right; }
548
+ .ui-datepicker-rtl .ui-datepicker-group { float:right; }
549
+ .ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
550
+ .ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header { border-right-width:0; border-left-width:1px; }
551
+
552
+ /* IE6 IFRAME FIX (taken from datepicker 1.5.3 */
553
+ .ui-datepicker-cover {
554
+ display: none; /*sorry for IE5*/
555
+ display/**/: block; /*sorry for IE5*/
556
+ position: absolute; /*must have*/
557
+ z-index: -1; /*must have*/
558
+ filter: mask(); /*must have*/
559
+ top: -4px; /*must have*/
560
+ left: -4px; /*must have*/
561
+ width: 200px; /*must have*/
562
+ height: 200px; /*must have*/
563
+ }/*
564
+ * jQuery UI Progressbar 1.8.9
565
+ *
566
+ * Copyright 2011, AUTHORS.txt (http://jqueryui.com/about)
567
+ * Dual licensed under the MIT or GPL Version 2 licenses.
568
+ * http://jquery.org/license
569
+ *
570
+ * http://docs.jquery.com/UI/Progressbar#theming
571
+ */
572
+ .ui-progressbar { height:2em; text-align: left; }
573
+ .ui-progressbar .ui-progressbar-value {margin: -1px; height:100%; }
css/tabber.css DELETED
@@ -1,109 +0,0 @@
1
- /* $Id: example.css,v 1.5 2006/03/27 02:44:36 pat Exp $ */
2
-
3
- /*--------------------------------------------------
4
- REQUIRED to hide the non-active tab content.
5
- But do not hide them in the print stylesheet!
6
- --------------------------------------------------*/
7
- .tabberlive .tabbertabhide {
8
- display:none;
9
- }
10
-
11
- /*--------------------------------------------------
12
- .tabber = before the tabber interface is set up
13
- .tabberlive = after the tabber interface is set up
14
- --------------------------------------------------*/
15
- .tabber {
16
- }
17
- .tabberlive {
18
- margin-top:1em;
19
- }
20
-
21
- /*--------------------------------------------------
22
- ul.tabbernav = the tab navigation list
23
- li.tabberactive = the active tab
24
- --------------------------------------------------*/
25
- ul.tabbernav
26
- {
27
- margin:0;
28
- padding: 3px 0;
29
- border-bottom: 1px solid #778;
30
- font: bold 12px Verdana, sans-serif;
31
- }
32
-
33
- ul.tabbernav li
34
- {
35
- list-style: none;
36
- margin: 0;
37
- display: inline;
38
- }
39
-
40
- ul.tabbernav li a
41
- {
42
- padding: 3px 0.5em;
43
- margin-left: 3px;
44
- border: 1px solid #778;
45
- border-bottom: none;
46
- background: #DDE;
47
- text-decoration: none;
48
- }
49
-
50
- ul.tabbernav li a:link { color: #448; }
51
- ul.tabbernav li a:visited { color: #667; }
52
-
53
- ul.tabbernav li a:hover
54
- {
55
- color: #000;
56
- background: #AAE;
57
- border-color: #227;
58
- }
59
-
60
- ul.tabbernav li.tabberactive a
61
- {
62
- background-color: #fff;
63
- border-bottom: 1px solid #fff;
64
- }
65
-
66
- ul.tabbernav li.tabberactive a:hover
67
- {
68
- color: #000;
69
- background: white;
70
- border-bottom: 1px solid white;
71
- }
72
-
73
- /*--------------------------------------------------
74
- .tabbertab = the tab content
75
- Add style only after the tabber interface is set up (.tabberlive)
76
- --------------------------------------------------*/
77
- .tabberlive .tabbertab {
78
- padding:5px;
79
- border:1px solid #aaa;
80
- border-top:0;
81
-
82
- /* If you don't want the tab size changing whenever a tab is changed
83
- you can set a fixed height */
84
-
85
- /* height:200px; */
86
-
87
- /* If you set a fix height set overflow to auto and you will get a
88
- scrollbar when necessary */
89
-
90
- /* overflow:auto; */
91
- }
92
-
93
- /* If desired, hide the heading since a heading is provided by the tab */
94
- .tabberlive .tabbertab h2 {
95
- display:none;
96
- }
97
- .tabberlive .tabbertab h3 {
98
- display:none;
99
- }
100
-
101
- /* Example of using an ID to set different styles for the tabs on the page */
102
- .tabberlive#tab1 {
103
- }
104
- .tabberlive#tab2 {
105
- }
106
- .tabberlive#tab2 .tabbertab {
107
- height:200px;
108
- overflow:auto;
109
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
images/logo.gif CHANGED
Binary file
images/logo.png CHANGED
Binary file
images/{progress.gif → progressBarLong.gif} RENAMED
File without changes
install.xcloner.php CHANGED
@@ -11,23 +11,15 @@ function com_install(){
11
 
12
  if( is_callable( array( 'JFactory', 'getDBO' ))) {
13
  $database = JFactory::getDBO();
 
 
14
  }
15
  $mypath = dirname(__FILE__);
16
 
17
- @chmod("components/com_xcloner/cloner.config.php", 0777);
18
- @mkdir("backups", 0777);
19
- @chmod("backups", 0777);
20
- @chmod("components/com_xcloner/configs", 0777);
21
- @chmod("components/com_xcloner/browser", 0755);
22
- @chmod("components/com_xcloner/", 0755);
23
- @chmod("components/com_xcloner/index.php", 0755);
24
- @chmod("components/com_xcloner/index2.php", 0755);
25
- @chmod("components/com_xcloner/cloner.cron.php", 0755);
26
-
27
  error_reporting( E_ALL ^ E_NOTICE );
28
 
29
  //add new admin menu images
30
- $database->setQuery("UPDATE #__components SET admin_menu_img = 'components/com_xcloner/images/xcloner.png' WHERE admin_menu_link = 'option=com_xcloner'");
31
- $database->query();
32
  }
33
  ?>
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 ADDED
@@ -0,0 +1,172 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ $(document).ready(function() {
2
+
3
+ var globalUrl;
4
+ var step = "r1";
5
+ var count = 0;
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){
20
+
21
+ return (bytes/conv).toFixed(2);
22
+
23
+ }
24
+ function appendIcon(icon){
25
+
26
+ return '<span class="ui-icon ui-icon-'+icon+'" style="float:left;"></span>';
27
+
28
+ }
29
+
30
+ function xclonerRecurseMYSQL(url){
31
+
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
+ }
73
+
74
+
75
+ });
76
+ }
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
+ }
108
+
109
+
110
+ });
111
+ }
112
+
113
+ function xclonerGetJSON(url){
114
+
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
+ });
150
+
151
+ }
152
+
153
+ });
154
+
155
+ }
156
+
157
+ $("#retry").click(function(){
158
+ $("#error").hide();
159
+ $("#errorText").empty();
160
+ if(step == "r1"){
161
+ xclonerRecurseMYSQL(globalUrl);
162
+ }
163
+ else
164
+ if(step == "r2"){
165
+ xclonerRecurseJSON(globalUrl);
166
+ }
167
+ else if(step == "r3"){
168
+ xclonerGetJSON(globalUrl);
169
+ }
170
+ });
171
+
172
+ });
javascript/jquery-ui-1.8.9.custom.min.js ADDED
@@ -0,0 +1,781 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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