@blog.justoneplanet.info

日々勉強

JavaScriptとPHPの配列の扱い

そういえば配列における「参照渡し」と「値渡し」の挙動がJavaScriptとPHPで異なっていたので書き留めておくことにする(・∀・)!!

■JavaScript

以下のようにJavaScriptでは、関数に配列を渡すと参照渡しとなる。

var ary = ['a', 'b', 'c'];
var sample = function(ary){
    ary.pop();
}
console.log(ary);// ['a', 'b', 'c']
alert('sample');
sample(ary);
console.log(ary);// ['a', 'b']

ちなみにalertはconsoleが上手く作動しなかったために使用した。

■PHP

以下のようにPHPでは、関数に配列を渡すとPHP4では値渡しとなる。

$ary = array('a', 'b', 'c');
function sample($ary){
    array_pop($ary);
}
var_dump($ary);
sample($ary);
var_dump($ary);

(関数内で配列を変更したい場合、)JavaScriptと同じ挙動をPHPで再現するには以下のように記述する必要がある。

$ary = array('a', 'b', 'c');
function sample(&$ary){
    array_pop($ary);
}
var_dump($ary);
sample($ary);
var_dump($ary);

リソースを節約するには参照渡しを明示したほうがイイね( ^ω^)

Modernizrにjsを追記して簡単にHTML5やCSS3の対応を確認する

以下を先頭に書く。

javascript:

Modernizrのソースを次にペーストしたら以下のソースを書く。

(function(obj){
	var txt = '';
	for(var i in obj){
		txt += i + ' : ' + obj[i] + '\n';
	}
	alert(txt);
})(window.Modernizr);

そうするとHTML5への対応やCSS3への対応がアラートされる。

Modernizr

頻繁に対応状況が変わるわけでないので無駄な作業な気がした。(´_`。)

■参考

http://www.modernizr.com/

ブラウザから位置情報を取得する

Geolocation APIを利用して取得。実装していないブラウザの為にGoogle Gearsを使用しても取得できる。

■Gears

使う準備をする。以下を書くだけで良い。

<script type="text/javascript" src="http://code.google.com/intl/ja/apis/gears/gears_init.js"></script>

■ソースコード

if(navigator.geolocation) {
	alert('geolocation');
	navigator.geolocation.getCurrentPosition(
		function(position){
			alert(position.coords.latitude + ',' + position.coords.longitude)
		},
		function(error){
			switch(error.code){
				case error.PERMISSION_DENIED :
					alert('Forbidden to use the Geolocation API.');
					break;
				case error.POSITION_UNAVAILABLE :
					alert('Location providers reported an internal error.');
					break;
				case error.TIMEOUT :
					alert('Timeout.');
					break;
				case error.UNKNOWN_ERROR :
				default :
					alert('Failed due to an unknown error.');
					break;
			}
		}
	);
}
else if(typeof google != 'undefined' && typeof google.gears != 'undefined'){
	alert('gears');
	google.gears.factory.create('beta.geolocation').getCurrentPosition(
		function(position){
			alert(position.coords.latitude + ',' + position.coords.longitude)
		},
		function(error){
			alert('error : ' + error.message);
		}
	);
}
else{
	alert('sorry');
}

Chrome LiteはGearsを搭載しているのでandroidでも位置情報が取得できる。

PHPで画像を指定サイズにする

画像のアスペクト比を維持しながら指定のサイズに近づけた後、はみ出した部分を切り落とす感じだ。

    
$width  = 240;
$height = 320;
$filename = '0008.jpg';
$size = getimagesize($filename);
$image = new Imagick($filename);
$image->setCompressionQuality(30);
if($size[1] < $size[0] * ($height / $width)){
    $image->thumbnailImage(0, $height);
    $imageWidth = (int) (($height / $size[1]) * $size[0]);
    $image->chopImage(($imageWidth - $width) / 2 , 0, 0, 0);
    $image->chopImage(($imageWidth - $width) / 2 , 0, $width, 0);
    $image->chopImage($width , $height, $width, $height);
}
else{
    $image->thumbnailImage($width, 0);
    $imageHeight = (int) (($width / $size[0]) * $size[1]);
    $image->chopImage(0, ($imageHeight - $height) / 2, 0, 0);
    $image->chopImage(0 , ($imageHeight - $height) / 2, 0, $height);
    $image->chopImage($width , $height, $width, $height);
}
$image->writeImage('sample.jpg');

GDとImageMagickを使用。ホントはImageMagickだけで大丈夫なはずなんだが、サイズの取得が上手く出来なくて…

ImageMagickとswftoolsをインストールしよう

■ImageMagick

ImageMagickのインストールだ。

yum install ImageMagick
yum install ImageMagick-devel

今回はPHPから使うので、以下のコマンドを実行する。

pecl install imagick
vi /etc/php.d/imagick.ini

上述のimagick.iniがないはずなので、同じディレクトリのファイルをコピーする。記述内容は以下の1行で良い。

extension=imagick.so

再起動する。

/etc/init.d/httpd restart

これで使えるようになったはずだ。

■swftools

画像ファイルをswfに変換する得体のしれないツールだ。

cd /home/admin
wget http://www.swftools.org/swftools-2009-08-24-2042.tar.gz
tar -xzvf swftools-2009-08-24-2042.tar.gz
./configure
make
make install

美人時計(bijin-tokei)の写真を全部集めよう

巷で話題の美人時計。全ての写真を集める方法をご紹介。

PHPだと以下のようになる。

■bijin.php

tie-upディレクトリがあるので、こちらの方が完璧に集まるはずだ。177人のtie-upも分けて収集可能。

<?php
//美人スクリプト
chdir(dirname(__FILE__));
for($s = 0; $s < 24; $s++){
	for($t = 0; $t < 60; $t++){
		$filename = sprintf('%02d%02d', $s, $t);
		$command = "wget http://www.bijint.com/jp/img/clk/{$filename}.jpg --referer=http://www.bijint.com/jp/";
		system($command, $rv);
		print($command . ':' . $rv . "\n");
	}
}
for($s = 0; $s < 24; $s++){
	for($t = 0; $t < 60; $t++){
		$filename = sprintf('%02d%02d', $s, $t);
		$command = "wget http://www.bijint.com/jp/img/clk/tie-up/{$filename}.jpg --referer=http://www.bijint.com/jp/ -O tie_up_{$filename}.jpg";
		system($command, $rv);
		print($command . ':' . $rv . "\n");
	}
}

PHPを実行できない人もいるだろう。以下のhtmlをブラウザで実行すればキャッシュとして写真がストックされるはずだ。

■bijin.html

JavaScriptを使用してブラウザにキャッシュさせる手法。

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>美人時計(bijin-tokei)の写真を全部集める</title>
</head>

<body>
<iframe src="http://www.bijint.com/cache/0000.html" id="iframe" width="900" height="550">
</iframe>
<p id="time"></p>
</body>
<script type="text/javascript">
var hour = 0;
var minute = 0;
if(!!(window.attachEvent && !window.opera)){
    document.getElementById('iframe').onreadystatechange = function(){
        if(this.readyState === 'complete'){
		    chageSrc();
        }
    }
}
else{
    document.getElementById('iframe').onload = function(){
	    chageSrc();
    }
}
function chageSrc(h, m){
    if(minute > 59){
        minute = 0;
        hour++;
    }
    var h = (hour < 10)? ('0' + hour) : hour;
    var m = (minute < 10)? ('0' + minute) : minute;
    if(hour < 24){
        document.getElementById('iframe').src = 'http://www.bijint.com/cache/' + h + '' + m + '.html';
        document.getElementById('time').innerHTML = (h + ':' + m + '<br />');
    }
    minute++;
}
</script>
</html>

ieではiframeのsrcを入れ替えてもonloadイベントが発生しないらしい。

androidでオプションメニューを作る

■MainActivity

以下のようにするとオプションメニューを実装することができる。

package info.justoneplanet.android.usemenu;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        super.onCreateOptionsMenu(menu);
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.menu, menu);
        return true;
    }
    
    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        switch(item.getItemId()){
        case R.id.settings:
            //startActivity(new Intent(this, Setting.class));
            return true;
        }
        return false;
    }
}

/res/menu/menu.xml

以下のように記述してメニューの項目を実装する。

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:id="@+id/settings"
        android:title="@string/setting"
        android:alphabeticShortcut="@string/setting_shortcut" />
</menu>

androidで設定画面を作る

androidでは簡単に設定画面が実装できる。

■設定画面

PreferenceActivity

まぁ、こんな感じ。setContentView(R.layout.main);ではなくaddPreferencesFromResource(R.layout.main);を使用する。

package info.justoneplanet.android.usepreference;

import android.os.Bundle;
import android.preference.PreferenceActivity;

public class MainActivity extends PreferenceActivity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.layout.main);
    }
}

res/layout/main.xml

どちらかというとxmlファイルの記述量の方が多い。

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceScreen
        android:title="Group1"
        android:summary="the setting of group 1">
        <PreferenceCategory android:title="Check">
            <CheckBoxPreference
	            android:key="check"
	            android:title="check"
	            android:summary="check!"
	            android:defaultValue="true" />
        </PreferenceCategory>
        <PreferenceCategory android:title="ID">
            <EditTextPreference
                android:key="name"
                android:title="name"
                android:summary="Input your name."
                android:defaultValue="" />
            <EditTextPreference
                android:key="pass"
                android:title="pass"
                android:summary="Input your password."
                android:defaultValue="" />
        </PreferenceCategory>
        <PreferenceCategory android:title="List">
            <ListPreference
                android:key="list"
                android:title="list"
                android:summary="this is a list of preference"
                android:defaultValue=""
                android:entries="@array/prference"
                android:entryValues="@array/prferenceval" />
        </PreferenceCategory>
    </PreferenceScreen>
</PreferenceScreen>

res/values/arrays.xml

ListPreferenceの中身は別ファイルにしておいた。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string-array name="prference">
        <item>selection 1</item>
        <item>selection 2</item>
        <item>selection 3</item>
    </string-array>
    <string-array name="prferenceval">
        <item>1</item>
        <item>2</item>
        <item>3</item>
    </string-array>
</resources>

■設定値の使用

以下のようにするとアプリケーションから設定値を使用することができる。

SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
String name = sharedPreferences.getString("name", "");
String pass = sharedPreferences.getString("pass", "");

androidでインテントフィルタを使ってみる

以下のように起動される側のアクティビティを定義する。

package info.justoneplanet.android.useintent;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.widget.TextView;

public class FilterActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.filter);
        if(!getIntent().getAction().equals(Intent.ACTION_MAIN)){
            Uri uri = getIntent().getData();
            TextView mText = (TextView) findViewById(R.id.text);
            mText.setText(uri.toString());
        }
    }
}

というかManifestファイルが重要だ。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="info.justoneplanet.android.useintent"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".MainActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity android:name=".FilterActivity"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <category android:name="android.intent.category.BROWSABLE" />
                <data android:scheme="http://" />
            </intent-filter>
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="4" />
</manifest> 

まぁ、こんな感じ。

androidでアプリケーションから別のアプリケーションを立ち上げる

以下のようにIntentを使用すると簡単に実装することができる。

package info.justoneplanet.android.useintent;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        Button mButton = (Button) findViewById(R.id.btn_browser);
        mButton.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                Intent intent = new Intent();
                intent.setClassName("com.android.browser", "com.android.browser.BrowserActivity");
                startActivity(intent);
            }
        });
    }
}

まぁ、こんな感じ。ポイントは以下の記述。

intent.setClassName("パッケージ名", "クラス名");

また、以下のようにしてURIに対応したアプリケーションを呼び出すことができる。

package info.justoneplanet.android.useintent;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class MainActivity extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        Button mButton = (Button) findViewById(R.id.btn_browser);
        mButton.setOnClickListener(new OnClickListener()
        {
            @Override
            public void onClick(View v)
            {
                Intent intent = new Intent();
                Uri uri = Uri.parse("http://google.com");
                intent.setAction(Intent.ACTION_VIEW);
                intent.setData(uri);
                startActivity(intent);
            }
        });
    }
}