<?php

define
('PSCAN_MAX_CLIENT'10);
define('PSCAN_TTL'600);

$lock_file "./pscan_lock_list.txt"// $ chmod 666 


$addr $_SERVER["REMOTE_ADDR"];
$port = -1;
$timeout 5;

#$addr = "211.134.87.181";

$output="";
$msg="";
if(!
pscan_check_input($port$msg)){

  
$output=$msg;

}else{
  
  if(
pscan_get_lock($lock_filePSCAN_MAX_CLIENT$errcode )){

    
$output .= "$addr の $port 番ポートに接続結果: ";
    if(
pscan_scan_port($addr$port$msg$timeout)){
      
$output .= "(・∀・) 成功";
    }else{
      
$output .= "(・A・) 失敗";
      
$output .=  "<ul>\n";
      
$output .=  "<li>ポートを使用するソフトウェアは起動されていますか?\n";
      
$output .=  "<li>ポート番号に間違いはありませんか?\n";
      
$output .=  "<li>パーソナルファイアウォールを使用している場合は設定変更が必要かもしれません。\n";
      
$output .=  "<li>ルーターを使用している場合は設定変更が必要かもしれません。\n";
      
$output .=  "</ul>\n";
    }

    if(!
pscan_release_lock($lock_file)){
      
error_log("pscan_debug: unlock() failed.");
    }

  }else{
    
$output .= "大変混雑しているようです。時間をおいて再度度チャレンジしてください。";
  }
}


?>

<html>
<head>
<title>
簡易TCPポートスキャンスクリプト
</title>
</head>
<body>


<b>取り扱い説明</b><p>
<ul>
<li><font color="red">まず最初にポートを使用するソフトウェア(例.Winny, WinMX, BitTorrent等)を起動しておきます。</font>次にそのソフトウェアが使用するポート番号を「チェックしたいポート番号」欄に入力してボタンを押すと、接続試行結果が表示されます。
<li>このスクリプトは指定されたポートに対してTCP接続を試みます。
タイムアウトは<?=$timeout?> 秒です。
<li>プロキシサーバーを経由してこのページにアクセスしている場合は正しい診断ができません。
</ul>
<p>


<form method="GET" action="<?= $_SERVER["PHP_SELF"?>">
<table cellpadding="5">
<tr>
<td>あなたのパソコン等のアドレス </td>
<td><?= $addr ?></td>
</tr>
<tr>
<td>チェックしたいポート番号</td>
<td><input type="text" name="port" value=""></td>
</tr><td>
<input type="submit" value="ポートが開いているかチェックする">
</td>
</tr>
</table>
</form>


<?= $output ?>


<div align="right"><font size=2><a href="./port_scan.phps">スクリプトソース</a></font></div>
</body>
</html>

<?php

//
//functions
//

function pscan_release_lock($file){

  
$fp fopen($file,  "r+");
  if(!
$fp){
    return 
false;
  }
  
  if(!
flock($fpLOCK_EX)){
    return 
false;
  }

  
// IPリスト読込
  
rewind($fp);
  
$iplist=array();
  while(!
feof($fp)){
    
$line fgets($fp4096);
    
$line trim($line);
    if(!
preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\t\d+/"$line)) continue;
    list(
$ipaddr$time) = split("\t"$line);
    
    if(
$ipaddr == $_SERVER["REMOTE_ADDR"]){
      continue;
    }
    
    if(
$time PSCAN_TTL <  time()){
      continue;
    }
    
    
$iplist[$ipaddr] = $time;
    
  }
  
  
// IPリスト書込み
  
stream_set_write_buffer($fp0);
  
ftruncate($fp0);
  
rewind($fp);
  foreach(
array_keys($iplist) as $ipaddr){
    
$time $iplist[$ipaddr];
    
$line "$ipaddr\t$time";
    
fputs($fp"$line\n");
  }

  
flock($fpLOCK_UN);
  
fclose($fp);

  return 
true;

}

function 
pscan_get_lock($file$n_max, &$errcode){

  
// ファイルオープン
  
$fp fopen($file,  "r+");
  if(!
$fp){
    if(!
file_exists($file)){
      
$fp fopen($file"w");
    }
  }

  if(!
$fp){
    
$errcode 1001;
    return 
false;
  }
  
  
// ロック
  
if(!flock($fpLOCK_EX)){
    
$errcode 1002;
    return 
false;
  }

  
// IPリスト読込み
  
rewind($fp);
  
$iplist=array();
  while(!
feof($fp)){
    
$line fgets($fp4096);
    
$line trim($line);
    if(!
preg_match("/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\t\d+/"$line)) continue;
    list(
$ipaddr$time) = split("\t"$line);

    if(
$time PSCAN_TTL <  time()){
      continue;
    }

    
$iplist[$ipaddr] = $time;
  }

  
//IPリストチェック
  
if(count($iplist) >= $n_max){ //クライアント数制限
    
flock($fpLOCK_UN);
    
fclose($fp);
    
$errcode 1003;
    return 
false;
  }else if(
array_key_exists($_SERVER["REMOTE_ADDR"], $iplist)){ //重複制限
    
flock($fpLOCK_UN);
    
fclose($fp);
    
$errcode 1004;
    return 
false;
  }    

  
// IPリスト書込み
  
$iplist[$_SERVER["REMOTE_ADDR"]] = time();
  
stream_set_write_buffer($fp0);
  
ftruncate($fp0);
  
rewind($fp);
  foreach(
array_keys($iplist) as $ipaddr){
    
$time $iplist[$ipaddr];
    
$line "$ipaddr\t$time";
     
fputs($fp"$line\n");
  }

  
/*
  stream_set_write_buffer($fp, 0);
  fseek($fp, 0,SEEK_END);

  $line = $_SERVER["REMOTE_ADDR"] . "\t" . time();
  fputs($fp, "$line\n");
  */

  
flock($fpLOCK_UN);
  
fclose($fp);

  return 
true;
 
}


function 
pscan_check_input(&$n_port, &$msg){

  if(empty(
$_GET["port"]) ){
    
$msg ="ポート番号が未入力です<p>";
    return 
false;
  }

  
$n_port $_GET["port"];

  if(!
is_numeric($n_port)){
    
$msg ="不正なポート番号です";
    return 
false;
  }
  
  if(
$n_port || $n_port 65536){
    
$msg "不正なポート番号です: $n_port<p>";
    return 
false;
  }
  
  return 
true;
}

function 
pscan_scan_port($addr$port, &$msg$timeout=5){
  
$old error_reporting(E_ALL E_WARNING);
  
$fp fsockopen ($addr$port$errno$errstr$timeout);
  
error_reporting($old);
  if (!
$fp) {
    
$msg "$errstr ($errno)\n";
    return 
false;
  } else{
    return 
true;
  }
}

?>