sidewalkcafe blog

日々是好日

jquery.xdomainajax.jsが動かなくなった

jsでクロスドメインのHTMLスクレイピングが使えるようになるjquery.xdomainajax.jsだけど、
しばらく前から使えないようになった。

結論

jquery.xdomainajax.jsの中身を以下のように変える

//古いデータ 18行目くらい
YQL = 'http' + (/^https/.test(protocol)?'s':'') + '://query.yahooapis.com/v1/public/yql?callback=?',
query = 'select * from html where url="{URL}" and xpath="*"';
//新しいデータ 18行目くらい
YQL = 'http' + (/^https/.test(protocol)?'s':'') + '://query.yahooapis.com/v1/public/yql?callback=?&env=store%3A%2F%2Fdatatables.org%2Falltableswithkeys',
query = 'select * from htmlstring where url="{URL}" and xpath="*"';

解説

jquery.xdomainajax.jsがクロスドメインの壁を超えるために、Yahoo!YQL というサービスを使ってたのだけど、それが使えなくなったのでURLを書き換えることで使えるようになったみたい。
ただ、返ってくるデータが生テキストからタグエスケープ済みのテキストデータになってるので、このままではセレクタの呼び出しや検索ができない。なので読み出し側も修正が必要。

呼び出し側の修正

//古いデータ resspnseTextをそのままjQueryオブジェクトに変換すればHTMLタグ化できた
$.ajax({  
    url: 'http://yahoo.co.jp/',
    type: 'GET',  
    success: function(data) {  
        content = $(data.responseText);
        $('body').append(content);
    }      
});  
//新しいデータ resspnseTextの中に<result>があり、その中にエスケープされたテキストが入ってるので
//オブジェクト化→アンエスケープ→オブジェクト化という手順を踏んでみた
$.ajax({  
    url: 'http://yahoo.co.jp/',
    type: 'GET',  
    success: function(data) {  
        content = $($(data.responseText).text());
        $('body').append(content);
    }      
});  

もっと良い方法があったら教えて下さい。

正規表現チェックサイト

正規表現チェック
RegexPlanet - Online Regular Expression (Regex) Testing and Cookbook for: Go, Haskell, Java, JavaScript, .Net, Perl, PHP, Python, Ruby, Tcl & XRegExp

色んなスクリプトでのチェツクが出来るのでオススメ

管理ユーザがいなくなったので何もできない(Mac OS 10.6)

メインユーザの管理者権限が外れて通常ユーザーになってしまったため、諸々の操作(環境設定変更、インストール等)ができなくなった。
なんか他でも同様の症状が出てるみたい。で、対処法を見るがなかなか上手く行かなかった。
がちゃがちゃやって上手くいった時の対応。

<参考>
Macで管理者権限がなくなってしまった時の対処方法: おたくマニアのココロ

A-Liaison BLOG: パスワードが無くなってログインできない Mac に無理矢理ログインする方法

対処法:通常ユーザに管理者権限を与える

基本的には上のリンクの通りにすれば良いんだけど、「com.apple.DirectryServices.plist」が読み込めなかったので代わりに「com.apple.DirectoryServicesLocal.plist」を読み込んで事なきを得た。

シングルユーザーモードMacを起動

再起動+起動時に「コマンド(リンゴマーク)」+「S」キーでシングルユーザーモードを立ち上げる
真っ黒なコンソールっぽい画面になったらOK

ハードディスクを編集可能にする

/sbin/mount -uw /

と打ち込んでハードディスクを再マウント、編集可能にする

/sbin/fsck -fy

と打ち込んでディスクチェックをしても良いのだけど割愛。調子が悪ければ要チェック。

ディレクトリサービスを読み込み、起動

launchctl load /System/Library/LaunchDaemons/com.apple.DirectoryServicesLocal.plist

「DirectoryServices」がnot fileになるので「DirectoryServicesLocal」を読み込み。

dscl localonly

で起動。頭が「>」に変われば起動成功

ディレクトリを移動

cd /Local/Default/Groups/

目的のディレクトリ階層まで「cd」で移動

管理権限付与

append admin GroupMembership 'username'

ユーザーに管理者権限を与えるコマンド。
'username'の部分に自分のユーザー名を入れる

ちなみに、うちのキーボードがおかしいのか配列が変わってたので、「'」の文字は「*(け)」の位置になってた(シフトキー不要)

mac mini(Mac OS 10.6 Snow Leopard Server)の初期設定トラブル

手持ちのMacが壊れたので、周辺機器が使えるOS 10.6以下の中古Macを探しにソフマップへ。
ちょうどあったMac miniを購入。

サーバタイプは不人気だという事で少し安かった。
初期設定が特殊なんだろうか・・・、以下と同じ症状がでた。

mac mini 中古で購入したが「ようこそ画面」の「続ける」ボタンを押せない
https://discussionsjapan.apple.com/thread/10123941

https://discussionsjapan.apple.com/servlet/JiveServlet/showImage/2-100738175-16052/youkoso.jpeg
(上記フォーラムより転載)


・原因:システム時刻が初期化されているため地域設定が出ない

・対処方法:ターミナルからシステム時刻を変更

1.USBのDVDドライブを接続してインストールメディアから起動
 (Cキーを押しながら電源を立ち上げる)
2.メニューが表示されるまで進めて、上メニューの「ユーティリティ」から「ターミナル」を選ぶ
3.ターミナルが起動したらコマンド画面から時刻の変更をする。
(2016年1月1日12:00の場合は以下のように入力)
 date 010112002016
4.通常再起動

 OSはインストールされているので、そのままインストールを続けなくても大丈夫。
不具合があった場合は再インストールする。
システム時刻の確認は、ターミナルから「date」と入力すれば確認できる。
ターミナルで間違えた時刻を設定しても、地域を選べば自動的に現在時刻に変更される。

BBQの代わりにプロキシチェック(PHP)

2chのBBQはゴタゴタがあった余波で外部参照ができなくなった。
便利だったのになあ・・・


使えなくなったのは仕方ないけど荒らしは待ってくれない
他のブラックリストを使って対処するしかない。
なのでそれに対応したコードを考えてみた。
(まあ、今までBBQだったアドレスを他のDNSBLのアドレスに変えれば良いだけなんだけどw)

<html>
<head>
  <title>DNSBLチェック</title>
</head>
<body>
  <form action="" method="get">
    テスト用IP<input type="text" value="" name="ip" /><br />
    <input type="text" value="" name="comment" />
    <input type="submit" value="コメント送信" />
  </form>
<?php
  $ip = '';

// IP取得
  if(isset($_GET['ip']) && $_GET['ip']!=null && filter_var($_GET['ip'],FILTER_VALIDATE_IP)){
    $ip=$_GET['ip'];
  }else{
    $ip = $_SERVER['REMOTE_ADDR'];
  }

// メインルーチン
  if(isset($_GET['comment']) && $_GET['comment']!=null){
    if(dnsbllookup($ip)){
      echo('ERROR! プロキシ経由のコメントは出来ません。<br>');
      echo('IP='.$ip);
      exit();
    }else{
      echo(htmlspecialchars($_GET['comment']).'<br>');
      echo('IP='.$ip);
      exit();
    }
  }

// DNSBLチェック
function dnsbllookup($ip){
  $dnsbl_lookup=array("all.rbl.jp",
    "bl.spamcop.net",
    "zen.spamhaus.org");
  if($ip){
    $reverse_ip=implode(".",array_reverse(explode(".",$ip)));
    foreach($dnsbl_lookup as $host){
      if(checkdnsrr($reverse_ip.".".$host.".","A")){
        return true;
      }
    }
  }
    return false;
  }
?>

$dnsbl_lookupに配列でDNSBLのアドレスを渡す。
有効なDNSBLDNSBL Lookupとかで探すと良い。
適当に使ってみたけど、抜けてるIPが多いので複数設定する必要がある様子。
とりあえず設定してある3つは2chで拾ってきたもの。

flipsnapで写真をランダム表示する

ネイティブJsでも使える

スマホでスワイプ操作が出来る便利で簡単なjQueryプラグイン「flipsnap」だけど
flipsnap.jsというのを書いた - Webtech Walker
jQuery必須ではなく、ソースはネイティブjsで書かれてたので普通のjavascriptで動いた(@version 0.6.2で動作確認)

そこから、ランダムに無限表示できるような実装を考えてた

DOM読み込み寺にflipnap適応

window.onloadではなくDOMContentLoadedを使ってます

window.addEventListener("DOMContentLoaded", function(){
  $flipsnap = Flipsnap("#demo");
}, false);

fstouchendイベントから現在地を取得

  $flipsnap.element.addEventListener('fstouchend', function(ev) {
    $newPT =ev.newPoint;
  }, false);
  • ボタン移動をする場合は、newPointの取得が出来ないので直接$newPTの値を加算・減算する

一番端に来た時に新しい写真を追加

  • 最大ブロック数の記録用変数($maxPT)を用意しておく
  • 現実的には通信ラグがあるので端から2〜3番目に来た時に追加読み込みするのが良いと思う
    if($newPT >= $maxPT){
      $maxPT ++ ;
      pushhtml();
    }

//写真追加
function pushhtml(){
  //データ(配列)の数を計算
  $dataleng = $photodata.length-1;
  //配列の中からランダムなidを取得
  $photoid = Math.round( Math.random()*$dataleng);
  //追加するPタグノードを作成
  var pNode = document.createElement('p');
  //imageオブジェクトを作成
  var image = new Image();
  //画像URLを指定
  image.src = $photodata[$photoid];
  //ノードに画像を追加
  pNode.appendChild(image);
  //親タグにノードを追加
  document.getElementById('demo').appendChild(pNode);
  //リフレッシュで全体の幅を再取得
  $flipsnap.refresh();
}
  • image.onloadで画像を読み込んでから配置する事も可能だけど、その場合はrefreshのタイミングも読み込み後に指定しないと、端まで移動ができなくなる


まあこんなもんかな

1つのフォームに複数のボタンを設置して別々の処理をさせる(PHP+javascript)

1つのフォームの中に複数のsubmitボタンを設置して、それぞれ違う処理をさせるページを作ろうとしたけれどもけっこう難しかった

目的

jsonデータの内容を表示、編集をフォームで簡単にしたかった

内容

  • 4つのグループにそれぞれ3種類の入力フォームを設置(タイトル・文章・URL)
  • グループ毎に「編集」「削除」ボタンを設置
  • 4グループをまとめて「編集」するボタンを設置

グループ毎の入力フォーム

PHPで複数のボタンを配置したときの処理(forやwhileで設置した複数のボタンを判別)
を参考に
各入力フォームとsubmitのname属性を配列にすることで、それぞれのグループを作る

for($i = 0;$i < 4;$i++){
echo <<<__HTML__
グループ{$i}<br>
タイトル<input type="text" name="title[{$i}]" value=""><br>
文章<input type="text" name="text[{$i}]" value=""><br>
URL<input type="text" name="url[{$i}]" value=""><br>
<br>
<input type="submit" name="submit[{$i}]" value="編集"><br>
__HTML__;
}

あとはkey($_POST['submit'])でボタンの押されたグループを班別して対応する配列を取り出す

$group =key($_POST['submit']);
$title = $_POST['title'][$group];
$text = $_POST['text'][$group];
$url = $_POST['url'][$group];

ボタンの種類

FORMで送信ボタンと戻るボタンを2つつけてそれぞれ遷移先を変えたい - その他(プログラミング) - 教えて!goo
を参考に、「編集」「削除」ボタンを実装。ボタン内にonclick処理を追加する

function sendMode(data){
 document.getElementById("editmode").value=data;
}
//グループ毎に設置
<input type="submit" name="submit[{$i}]" value="編集" onclick="sendMode(1)"><br>
<input type="submit" name="submit[{$i}]" value="削除" onclick="sendMode(2)"><br>

//グループの外に1つだけ設置
<input type="hidden" id="editmode" name="editmode" value="0">

ボタンクリックでjavascriptを呼び出し、隠しフォームの値を書き換える
submitとonclickの実行タイミングがわからなかったけど、とりあえず動いてるから良しとするw


あとは受け取った$_POST["editmode"]の値によって処理を振り分ける

switch ($_POST["editmode"]) {
    case 0:
        //全体編集処理
        break;
    case 1:
        //グループ編集処理
        break;
    case 2:
        //グループ削除
        break;
}

う〜ん、submitのvalue内容で振り分けた方がスマートかな?

完成?

<?php
//postなら各種処理
if($_POST){

//分岐処理
switch ($_POST["editmode"]) {
    case 0:
        //全体編集処理
		echo("全グループを編集しました");
        break;
    case 1:
        //グループ編集処理
		$group =key($_POST['submit']);
		$title = $_POST['title'][$group];
		$text = $_POST['text'][$group];
		$url = $_POST['url'][$group];
		echo("グループ".$group."を編集しました<br>");
		echo("タイトル=".$title."<br>");
		echo("文章=".$text."<br>");
		echo("URL=".$url);
        break;
    case 2:
        //グループ削除
		$group =key($_POST['submit']);
		$_POST['title'][$group]="";
		$_POST['text'][$group]="";
		$_POST['url'][$group]="";
		echo("グループ".$group."を削除しました");
        break;
}

//保存処理  通常はcase毎に行う
$datasave = $_POST ;
}

//データ呼び出し処理
$output = $datasave ;

//html書き出し
?>
<html lang="ja-JP">
<head>
<meta charset="UTF-8" />
<script>
function sendMode(data){
 document.getElementById("editmode").value=data;
}
</script>
</head>
<body>
<h2>複数ボタンフォーム</h2>
<form method="post" action="">
<hr>
<?php
//グループ毎のフォーム書き出し
for($i = 0;$i < 4;$i++){
echo <<<__HTML__
グループ{$i}<br>
タイトル<input type="text" name="title[{$i}]" value="{$output['title'][$i]}"><br>
文章<input type="text" name="text[{$i}]" value="{$output['text'][$i]}"><br>
URL<input type="text" name="url[{$i}]" value="{$output['url'][$i]}"><br>
<br>
<input type="submit" name="submit[{$i}]" value="編集" onclick="sendMode(1)"><br>
<input type="submit" name="submit[{$i}]" value="削除" onclick="sendMode(2)"><br>
<hr>
__HTML__;
}

//全体編集・隠しフォーム・フッタ
?>
<input type="hidden" id="editmode" name="editmode" value="0"> 
<input type="submit" name="submit" value="全体編集"><br>
<hr>
</form>
</body>
</html>
  • 削除処理は保存内容を呼び出しunset()を使う
  • 保存はcase毎に処理を分ける