Брёд

27.02.2010

SSH и PHP

Рубрика: Программирование — admin @ 23:09

Сегодня появилась идея ( честно лучше бы ее не было ) для облегчения себе жизни.

Идея заключалась в следующем, имея ICQ робота мы отсылаем ему команду которую он обрабатывает, заходит на удаленный SSH сервер, выполняет там команду и наконец результат команды возвращает на обратно. Все естественно на PHP5.

Первым делом попался PECL модуль ssh2.

Пляски с бубном вокруг него породили статический SSH класс:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
<?php
/***
* R114 PHP-SSH class ver. 0.0.2b
* (c) 2010 R114, All rights reserved.
* URL: http://www.rostov114
* E-mail: info@rostov114.net
*/ 
class SSH
{
	/*
	 * Идантификатор содинения с SSH сервером
	 *
	 * @access	private
	 */
	private static $connection;
 
	/*
	 * Идантификатор shell режима
	 *
	 * @access	private
	 */
	private static $shell = FALSE;
 
	/*
	 * Метод использованный при логине
	 *
	 * @access	public
	 */
	public static $auth_method = FALSE;
 
	/*
	 * shell тип
	 *
	 * @access	public
	 */
	public static $shell_type = '';
 
	/*
	 * Будет ли функция exec выводить результат массивом или нет
	 *
	 * @access	public
	 */
	public static $return_exec_array = TRUE;
 
	/**
	 * Произвести подключение к SSH серверу
     	 *
	 * @access	public
	 * @param	string
	 * @param	int
	 * @param	array
	 * @param	array
	 * @return	bool
	 */
	public static function connect($host, $port = 22, $methods = array(), $callbacks = array())
	{
		if (!extension_loaded('ssh2'))
		{
			die('Please install package PECL: ssh2');
		}
 
		self::$connection = @ssh2_connect($host, $port, $methods, $callbacks);
 
		return is_resource(self::$connection);
	}
 
	/**
	 * Попытаться произвести логин на сервере
     	 *
	 * @access	public
	 * @param	string
	 * @param	string
	 * @return	bool
	 */
	public static function login($username, $password)
	{
		if (self::$connection === FALSE)
		{
			return FALSE;
		}
 
		$auth_methods = @ssh2_auth_none(self::$connection, $username);
 
 
		foreach ($auth_methods as $method)
		{
			switch ($method)
			{
				case 'password':
					$is_auth = @ssh2_auth_password(self::$connection, $username, $password);
					break;
 
				case 'publickey':
					#$is_auth = @ssh2_auth_pubkey_file(self::$connection, $username, 'test_key.rsa.pub', 'test_key.rsa', $password);
					$is_auth = FALSE;
					break;
 
				case 'keyboard-interactive':
					$is_auth = FALSE;
					break;
 
				default:
					$is_auth = FALSE;
					break;
 
			}
 
			if ($is_auth === TRUE)
			{
				self::$auth_method = $method;
				return TRUE;
			}
		}
 
		return FALSE;
	}
 
	/**
	 * Выполнить комманду (комманды) на удаленном сервере
     	 *
	 * @access	public
	 * @return	mixed
	 */
	public static function exec()
	{
        	if (is_resource(self::$shell) or self::$auth_method === FALSE or self::$connection === FALSE)
		{
			return FALSE;
		}
 
		$argv   = func_get_args();
 
		if (self::$return_exec_array === TRUE)
		{
			$return = array();
 
			foreach ($argv as $com)
			{
				$stream = @ssh2_exec(self::$connection, $com);
				@stream_set_blocking($stream, true);
				$return[] = @stream_get_contents($stream);
			}
 
			return $return;
		}
 
		$stream = @ssh2_exec(self::$connection, implode(' && ', $argv));
		@stream_set_blocking($stream, true);
 
		return @stream_get_contents($stream);
	}
 
	/**
	 * Перейти в shell режим
     	 *
	 * @access	public
	 * @return	bool
	 */
	public static function shell()
	{
		if (self::$auth_method === FALSE or self::$connection === FALSE)
		{
			return FALSE;
		}
 
		if (!is_resource(self::$shell))
		{
			self::$shell = @ssh2_shell(self::$connection, self::$shell_type);
		}
 
		$argv = func_get_args();
 
		foreach ($argv as $com)
		{
			@fwrite(self::$shell, $com.PHP_EOL);
		}
 
		return TRUE;
	}
}

Отличия от большинства других классов написанных с использованием функций ssh2:
1. Продуманные условия «против дурака»,
2. Компактный,
3. Может выполнить несколько exec команд за раз и вернуть результат 1 для всех команд или для каждого свой (массивом),
4. Понятный и читабельный код без идиотизма.

28.01.2010

Обработка Multi Scrape заспросов

Рубрика: Программирование — Метки: , , — admin @ 02:26

На этот раз мне захотелось еще раз вые выпиндриться, и сделать в своем scrape поддержку Multi Scrape запросов.
Долгие пляски вокруг $_GET, фактически ничего не дали но зато дал плоды $_SERVER['QUERY_STRING'].
Зацепившись за него минут за 15 накатал простенькую функцию которая выдает массив хеш-сумм переданные в URI. В случае если хотя бы одна хеш-сумма не будет равна 20 символам то функция завершиться с ошибкой Invalid info_hash.

Сама функция:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function scrape_parse_query()
{
    $info_hash = array();
    $query     = $_SERVER['QUERY_STRING'];
 
    $query = explode("&", $query);
 
    foreach($query as $k)
    {
        list($key, $value) = explode('=', $k);
        $key   = str_replace('?', '', $key);
	$value = urldecode($value);
 
        if($key == 'info_hash' && strlen($value) == 20)
        {
		$info_hash[] = bin2hex($value);
        }
        else
        {
            if(strlen($value) != 20 and $key == 'info_hash')
            {
		msg_die('Invalid info_hash');
            }
        }
    }
 
    return $info_hash;
}

На выходе у функции будет массив хеш-сумм (в BTIH).
Что с данными хеш суммами делать, решайте сами.
Кстати, чуть не забыл сказать, данная функция писалась под scrape на основе TorrentPier.

27.01.2010

Из compact в обычный вид

Рубрика: Программирование — Метки: , — admin @ 21:55

Недавно понадобилось протестировать собственный же анонсер, по всем критериям и один из них нормальная работа в compact режиме (т.е. пиров нам анонсер отдает в закодированном виде, что уменьшает в свою очередь трафик между сервером и клиентами).

Для того чтобы прекратить из compact в обычный вид написал функцию, которая до ужаса банальна, но работает:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
function peers_to_array($data)
{
	if (!is_array($data['peers']))
	{
		$new_peers = array();
 
		while (strlen($data['peers']) > 0)
		{
			list(, $ip)   = @unpack('N', substr($data['peers'], 0, 4));
			list(, $port) = @unpack('n', substr($data['peers'], 4, 6));
 
			$new_peers[] = array
			(
				'ip'   => long2ip($ip), 
				'port' => $port
			);
 
			$data['peers'] = substr($data['peers'], 6);
		}
 
		$data['peers'] = $new_peers;
		unset($new_peers);
	}
 
	return $data;
}

:) Как ее использовать я думаю объяснять не нужно.

Сайт работает на WordPress