Advertisement
Guest User

rep2/replace_proxy.php

a guest
Oct 27th, 2017
139
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.59 KB | None | 0 0
  1. <?php
  2. /*
  3. 置換プロキシ
  4.  
  5. 概要
  6. 指定したURLの内容を正規表現で抽出置換して出力するプロキシ。
  7. 置換ワードやリンクプラグインから使うことを想定。
  8. 埋め込みコードがないサイトや、埋め込みコードはあるがURLから生成できないサイトでもp2に埋め込めるようになる。
  9. iframeで埋め込んだり、JavaScriptで非同期取得したりできる。
  10. ヘッダだけを取得して返すこともできるので、短縮URLのリンク先を得ることも可能。
  11.  
  12. 設置場所
  13. rep2/replace_proxy.php
  14.  
  15. クエリーパラメータ
  16. p:検索パターン
  17.  preg_replaceのpatternの{^.*?検索パターン.*}msに相当
  18.  必須
  19. r:置換文字列
  20.  preg_replaceのreplacementに相当
  21.  必須
  22. i:入力文字エンコーディング
  23.  省略時自動判定
  24.  使えるものは↓参照
  25.  http://php.net/manual/ja/mbstring.supported-encodings.php
  26. o:出力文字エンコーディング
  27.  省略時入力文字エンコーディングと同じ
  28. h:ヘッダに対して処理するか否か
  29.  何かしら指定すると、コンテキストではなくヘッダに対して処理を行う。
  30.  ヘッダは改行(\n)区切りになり、content-type:text/plain:charset=utf-8で返る。
  31. l:キャッシュを保持する秒数。
  32.  省略すると1週間。
  33. u
  34.  URL。
  35.  必ず最後に指定すること。
  36.  
  37. リンクプラグインでの使用例
  38. ・なんとかデータベース
  39.  Match=^(http://\w+\.supleks\.jp/s/[0-9]+\.html)
  40.  Replace=atag<img class="preview-video-switch" src="img/show.png" data-video_url="replace_proxy.php?p=<div class=%22fldborder%22><textarea>(.*?)</textarea></div>&r=%5C1&u=\1" data-video_style="width:230px;height:315px;border:none">
  41.  なんとかデータベースの埋め込みコードを抜き取り、iframeで表示している。
  42. */
  43.  
  44. // HTTPレスポンスヘッダ関係の補助をするクラス
  45. class Header
  46. {
  47. private header = array();
  48. // 様々な形式のHTTPレスポンスヘッダをパースする
  49. function __construct(input = null) {
  50. switch (TRUE) {
  51. case input === null:
  52. case input === '':
  53. break;
  54. // 改行区切りの文字列形式
  55. case is_string(input):
  56. // 改行区切りにする
  57. this->parse_array_text(explode("\r\n", input));
  58. break;
  59. // 配列の場合
  60. case is_array(input):
  61. // 配列区切りの文字列形式
  62. if (array_values(input) === input) {
  63. this->parse_array_text(input);
  64. // 連想配列
  65. } else {
  66. this->header = input;
  67. }
  68. break;
  69. default:
  70. throw new Exception('inputが不正な形式です。');
  71. break;
  72. }
  73. }
  74. // 配列区切りの文字列形式のHTTPレスポンスヘッダをパースする
  75. private function parse_array_text(input) {
  76. header = array();
  77. foreach(input as k => v) {
  78. t = explode(':', v, 2);
  79. if( isset( t[1] ) )
  80. header[ trim(t[0]) ] = trim( t[1] );
  81. else {
  82. header[] = v;
  83. if( preg_match( "#^HTTP/[0-9\.]+\s+[0-9]+#",v, out ) )
  84. header[0] = out[0];
  85. }
  86. }
  87. this->header = header;
  88. }
  89. // ヘッダを全て出力
  90. function output(key = null) {
  91. if (key === null) {
  92. foreach (this->header as key => value) {
  93. header(key . ': ' . value);
  94. }
  95. } elseif (isset(this->header[key])) {
  96. header(key . ': ' . this->header[key]);
  97. } else {
  98. throw new Exception('このヘッダは存在しません。');
  99. }
  100. }
  101. // 文字列形式のHTTPレスポンスヘッダにする
  102. function build() {
  103. result = array();
  104. foreach (this->header as key => value) {
  105. result[] = key . ': ' . value;
  106. }
  107. return implode("\r\n", result);
  108. }
  109. // ヘッダを取り出す
  110. function get(key = null) {
  111. if (key === null) {
  112. return this->header;
  113. } elseif (!isset(this->header[key])) {
  114. return null;
  115. } else {
  116. return this->header[key];
  117. }
  118. }
  119. // ヘッダをセット
  120. function set(key, value) {
  121. this->header[key] = value;
  122. }
  123. }
  124.  
  125. function file_get_contents_cache(filename, use_include_path = false, context = null, offset = -1, maxlen = null) {
  126. require_once "Cache/Lite.php";
  127. global _conf;
  128. cache = new Cache_Lite(array(
  129. 'cacheDir' => _conf['cache_dir'] . '/',
  130. 'lifeTime' => 86400,
  131. 'automaticSerialization' => true,
  132. ));
  133.  
  134. if (!empty(context)) {
  135. options = stream_context_get_options(context);
  136. if (!isset(options['http'])) options['http'] = array('header' => '');
  137. if (!isset(options['http']['header'])) options['http']['header'] = '';
  138. } else {
  139. options = array('http' => array('header' => ''));
  140. }
  141. header = new Header(options['http']['header']);
  142. // 今のところはgzipのみ。deflateも使えるらしい
  143. header->set('Accept-Encoding', 'gzip');
  144.  
  145. cache_key = serialize(array(
  146. 'filename' => filename,
  147. 'options' => options,
  148. ));
  149.  
  150. // キャッシュを取得
  151. cache_data = cache->get(cache_key);
  152. // キャッシュがある場合
  153. if (cache_data !== FALSE) {
  154. foreach (array(
  155. 'ETag' => 'If-None-Match',
  156. 'Last-Modified' => 'If-Modified-Since'
  157. ) as key => value) {
  158. if (isset(cache_data[key])) header->set(value, cache_data[key]);
  159. }
  160. }
  161. // ヘッダを構築
  162. options['http']['header'] = header->build();
  163. subject = @file_get_contents(filename, use_include_path, stream_context_create(options));
  164. header = new Header(http_response_header);
  165. if (header->get(0) === 'HTTP/1.1 304 Not Modified') {
  166. return cache_data['content'];
  167. }
  168. if (subject === FALSE) {
  169. throw new Exception(filename . 'を開けませんでした。');
  170. }
  171. // 圧縮されていれば解凍する
  172. if (header->get('Content-Encoding') && (subject = zlib_decode(subject)) === FALSE) {
  173. throw new Exception(filename . 'のgzip圧縮を展開できませんでした。');
  174. }
  175. if (!cache->save(array(
  176. 'ETag' => !is_null(header->get('ETag')) ? header->get('ETag') : null,
  177. 'Last-Modified' => !is_null(header->get('Last-Modified')) ? header->get('Last-Modified') : null,
  178. 'content' => subject,
  179. ), cache_key)) {
  180. throw new Exception('キャッシュの保存に失敗しました。');
  181. }
  182. return subject;
  183. }
  184.  
  185. try {
  186. function mkdir_auto(pathname) {
  187. if (!file_exists(pathname)) {
  188. mkdir(pathname, 0777, true);
  189. }
  190. }
  191. define('INTERNAL_ENCODING', 'UTF-8');
  192.  
  193. require_once __DIR__ . '/../init.php';
  194.  
  195. _login->authorize(); // ユーザ認証
  196.  
  197. if (!isset(_GET['u'], _GET['p'], _GET['r'])) {
  198. throw new Exception('最低限必要なパラメータがセットされていません。');
  199. }
  200.  
  201. if (preg_match('/(?:\?|&)u=(.+)/', _SERVER['QUERY_STRING'], matches) < 1) {
  202. throw new Exception('URLが指定されていません。');
  203. }
  204. url = matches[1];
  205. unset(matches);
  206.  
  207. lifetime = isset(_GET['l']) ? _GET['l'] : 86400 * 7;
  208. options = array(
  209. 'lifeTime' => lifetime,
  210. 'errorHandlingAPIBreak' => TRUE
  211. );
  212.  
  213. // データを取得
  214. require_once "Cache/Lite.php";
  215. content_cache = new Cache_Lite(options + array(
  216. 'cacheDir' => _conf['cache_dir'] . '/replace_proxy/content/'
  217. ));
  218. mkdir_auto(_conf['cache_dir'] . '/replace_proxy/content');
  219. header_cache = new Cache_Lite(options + array(
  220. 'cacheDir' => _conf['cache_dir'] . '/replace_proxy/header/'
  221. ));
  222. mkdir_auto(_conf['cache_dir'] . '/replace_proxy/header');
  223. header = header_cache->get(url);
  224. if (header !== FALSE) unserialize(header);
  225. if ((content = content_cache->get(url)) === FALSE || header === FALSE) {
  226. if ((content = file_get_contents_cache(url)) === FALSE) {
  227. throw new Exception('データの読み込みに失敗しました。');
  228. }
  229. header = http_response_header;
  230.  
  231. if (!content_cache->save(content)) {
  232. throw new Exception('contentキャッシュの保存に失敗しました。');
  233. }
  234. if (!header_cache->save(serialize(header))) {
  235. throw new Exception('headerキャッシュの保存に失敗しました。');
  236. }
  237. }
  238.  
  239. if (!isset(_GET['h'])) {
  240. encoding = isset(_GET['i']) ? _GET['i'] : mb_detect_encoding(content);
  241.  
  242. // 文字エンコーディングを変換
  243. if (INTERNAL_ENCODING !== encoding) {
  244. content = mb_convert_encoding(content, INTERNAL_ENCODING, encoding);
  245. }
  246.  
  247. // データを置換
  248. if ((content = preg_replace('{^.*?' . _GET['p'] . '.*}ms', _GET['r'], content)) === NULL) {
  249.  
  250. throw new Exception('データの置換に失敗しました。');
  251. }
  252.  
  253. // 文字エンコーディングを戻す
  254. output_encoding = isset(_GET['o']) ? _GET['o'] : encoding;
  255. if (INTERNAL_ENCODING !== encoding) {
  256. content = mb_convert_encoding(content, encoding, INTERNAL_ENCODING);
  257. }
  258.  
  259. // ヘッダを出力
  260. foreach((array)header as h) {
  261. // Content-typeだけ取得する
  262. if (strpos(strtolower(h), 'content-type:') !== FALSE) {
  263. header(h);
  264. break;
  265. }
  266. }
  267. // 既定ヘッダの上書き
  268. header('Cache-Control: private');
  269. header('Pragma: ');
  270. // キャッシュ用
  271. etag = sha1(content);
  272. if (isset(_SERVER['HTTP_IF_NONE_MATCH']) && etag === _SERVER['HTTP_IF_NONE_MATCH']) {
  273. header('HTTP/1.1 304 Not Modified');
  274. } else {
  275. header('ETag: ' . etag);
  276. echo content;
  277. }
  278. // 出力
  279. } else {
  280. // データを置換
  281. if ((content = preg_replace('{^.*?' . _GET['p'] . '.*}ms', _GET['r'], impode("\n", header))) === NULL) {
  282. throw new Exception('データの置換に失敗しました。');
  283. }
  284. header('Content-type: text/plain; charset=utf-8');
  285. echo content;
  286. }
  287.  
  288. } catch(Exception e) {
  289. echo "エラー:" . e->getMessage();
  290. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement