@blog.justoneplanet.info

JavaScript、PHP、MySQLを使ったり

MySQLサーバーをインストールして初期設定をする

■インストール

yum install mysql-server

PHPから使う場合は以下のようにphp-mysqlもインストールする。

yum install php-mysql

MySQLにアクセスする。

mysql -u root

■パスワード

アクセスできるのは良いんだがパスワードが設定されてないのはイカン。(・ε・)

SET PASSWORD FOR root@localhost=PASSWORD('fugafuga');

■データベース

ちょっとデータベースを作ってみる。

CREATE DATABASE `sample`;

■テーブル

ちょっとテーブルを作ってみる。

USE `sample`;
CREATE TABLE  `sample`.`tbl1` (
    `id` INT( 11 ) NOT NULL AUTO_INCREMENT ,
    `name` VARCHAR( 255 ) NOT NULL ,
    PRIMARY KEY (  `id` )
) ENGINE = MYISAM ;

■文字コード

ネットで探してもなかなか適切な文献が見当たらない。凄く深いので結論だけまとめておく。

ちょっとPHPからデータを入れてみる。

$dbh = mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db(DB_NAME, $dbh);
$query = "INSERT INTO `tbl1`(`name`) VALUES('山田');";
$result = mysql_query($query);

phpMyAdminで見てみると以下のように文字化けする。

capture

MySQLのデフォルト文字コードはlatin1になっている為だ。アプリケーション側で表示するときは特に文字化けすることはないかもしれないが、管理上は非常に面倒なのでデフォルト文字コードをutf-8にする事を強く勧める。

my.cnf(my.ini)

以下のようにする。

[mysqld]
default-character-set=utf8
[client]
default-character-set=utf8

但しMySQLクライアントのコンパイルオプションによっては全然文字化けしまくる。従ってプログラム側での修正も必要だ。

PHP

mysql_connectを使う

mysql_connectを使用している場合は5.2.3以上が必須で、以下のようにクライアント側の文字コードを設定する。

$dbh = mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_set_charset('utf8', $dbh);
PDOを使う

PDOを使用している場合は以下のように、MySQLの設定ファイルを読み込み、ATTR_EMULATE_PREPARESをfalseにしてサーバーサイドPrepared Statementを使うようにする。

$dsn = 'mysql:host=' . DB_HOST . ';dbname=' . DB_NAME;
$dbh = new PDO(
    $dsn,
    DB_USER,
    DB_PASS,
    array(
        PDO::MYSQL_ATTR_READ_DEFAULT_FILE => '/etc/my.cnf'
    )
);
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

但し、MySQL<5.1の場合はクエリキャッシュが聞かないので注意が必要だ。現時点ではPDOでクライアント側の文字コードを指定する方法は無い。

誤り
  • 「SET NAMES utf8」クエリを発行する。
  • 「skip-character-set-client-handshake」をmy.cnfに記述する。
参考

「PHP5.2.3以前」かつ「PDOを使用できない」かつ「再コンパイルできない」とき文字コードの問題を完全に解決するのは不可能とのこと。

CentOSにおけるパッケージインストールまとめ

■ソースからインストール

ソースパッケージをダウンロードしてコンパイル・ビルド。(gcc・・・)

【メリット】

  • 環境に依存したどうこうに関係なくインストールできる。

インストールするときにインストールするマシン自身が自分でビルドする為。

【デメリット】

  • 「依存関係」の考慮が必要で面倒
  • 必要な他プログラムなどあれば別途自分でインストールする等

■RPMでインストール

あらかじめ別のマシンでコンパイルしたものをそのままコピーする。

【メリット】

  • 自分でコンパイルしないだけ簡単

【デメリット】

  • コンパイルしたマシンと環境が異なる場合は使えない
  • コンパイルしたマシンで指定したオプションに限定され、必要なオプションが指定できない
  • パッケージはあらゆる人が公開してるから、探したりダウンロードしたり記録したり、などが面倒

■yumでインストール

パッケージ群を公開しているリポジトリからRPMを探し、ダウンロードして、インストールしてくれるツール

【デメリット】

  • 依存関係や付属プログラムや、そもそもそれらの有無なども、すべて他人が決めたもの
  • たくさんのリポジトリを参照するようにyumに追加設定すると依存関係のトラブルが起きたりする

【ポイント】

リポジトリは信頼できるところにしておいたほうが良い。

  • ~redhat.com
  • 有名どころとか
  • 各ディストリビューションのベンダーなど・・・

Windows XPでPHPとimageMagickを使用する

■ImageMagick

以下のサイトからWindows版をダウンロードしてインストールする。

http://www.imagemagick.org/script/binary-releases.php?ImageMagick=pjjjn3udinf3ldej2osq7k8nj1#windows

Program Files配下などのスペースを含むパスにインストールせず、cドライブ直下が望ましいらしい。

環境変数

設定>コントロールパネル>システム>詳細設定>環境変数>システム環境変数

変数名はMAGICK_HOMEとし値はインストールしたパスを入力する。

■Microsoft Visual C++ 2005 SP1

以下のサイトからインストール

http://www.microsoft.com/downloads/details.aspx?familyid=200B2FD9-AE1A-4A14-984D-389C36F85647&displaylang=ja

■php_imagick

以下のサイトからインストールする。

http://www.sk89q.com/2010/03/vc6-windows-binaries-for-imagick-2-3-0/

リンクが切れている場合はここ

上手くいかない場合は以下のサイトのdllを使用した方が良いかもしれない。

http://valokuva.org/?page_id=50

extension_dir = "C:\xampp\php\ext"

php.iniが上述のような場合は「C:\xampp\php\ext」にファイルを配置する。

php.ini

以下の設定を追加(パスは環境に合わせて変更してください)

extension=php_imagick.dll

Windowsを再起動すると使用可能になる。

androidでアプリを作ってみる

今回のアプリはandroid marketで公開した「prime?」という名のアプリの全てのソースコードである。

■AndroidManifest.xml

今回はActivityを2つ使用するので、以下のようにactivity要素を加えないとアプリから使用できない。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="info.justoneplanet.android.primenumber"
      android:versionCode="2"
      android:versionName="0.2">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".PrimeNumberActivity"
                  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=".PrimeNumberListActivity"
                  android:label="@string/app_name_list">
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="3" />
</manifest>

■アクティビティ1

/src/info/justoneplanet/android/primenumber/PrimeNumberActivity.java

まず、初めに表示されるActivityを実装する。

package info.justoneplanet.android.primenumber;

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;

public class PrimeNumberActivity extends Activity {
    private static final int MENU1_ID = Menu.FIRST;
    private static final int MENU2_ID = Menu.FIRST + 1;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);// こいつでレイアウトのxmlを指定!

        Button validate = (Button) findViewById(R.id.button_validate);
        validate.setOnClickListener(// これがイベントだ!なんかコード量多し。
            new View.OnClickListener() {
                public void onClick(View v) {
                    TextView textView = (TextView) findViewById(R.id.result);
                    EditText editText = (EditText) findViewById(R.id.number);
                    Integer number = Integer.valueOf(editText.getText().toString());
                    int num = _isPrime(number, textView);
                    if(num == 0){
                        textView.setText("Prime!!");
                    }
                    else if(num < 0){
                        textView.setText("Not Prime!!");
                    }
                    else{
                        String str = Integer.toString(num);
                        textView.setText("Not Prime!! It will be divided by '" + str + "'");
                    }
                }
            }
        );
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        // メニューを押したとき
        boolean result = super.onCreateOptionsMenu(menu);
        menu.add(0, MENU1_ID, Menu.NONE, R.string.menu2);
        return result;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        // メニューが選択されたとき
        switch(item.getItemId()){
        case MENU1_ID:
            //Log.e("tag", "start");
            startActivity(new Intent(this, PrimeNumberListActivity.class));
            finish();
            return true;
        }
        return false;
    }

    /**
     *_isPrime
     * @param number
     * @return
     */
    private int _isPrime(Integer number, TextView textView)
    {
        if(number < 2){
            return -1;
        }
        for(int i = 2; i < number / 2 + 1; i++){
            textView.setText(Integer.toString(i));
            if(number % i == 0){
                return i;
            }
        }
        return 0;
    }
}

/res/layout/main.xml

上述のActivityのレイアウトを定義する。ボタンが上にあると押しにくいので下に配置した。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView
    android:id="@+id/result"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/msg_title_input"
    android:textSize="16dip"
    />
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="bottom"
        >
    <EditText
        android:id="@+id/number"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dip"
        android:inputType="number"
        android:textSize="26dip"
        android:maxLength="7"
        />
    <Button
        android:id="@+id/button_validate"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/button_validate"
        />
    </LinearLayout>
</LinearLayout>

■/src/info/justoneplanet/android/primenumber/PrimeNumberListActivity.java

まず、次のActivityを実装する。せっかくだからListActivityを継承する。

package info.justoneplanet.android.primenumber;

import java.util.ArrayList;

import android.app.Activity;
import android.app.ListActivity;
import android.content.Intent;
import android.os.Bundle;
import android.text.Layout;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.TextView;

public class PrimeNumberListActivity extends ListActivity {
    private static final int MENU1_ID = Menu.FIRST;
    private static final int MENU2_ID = Menu.FIRST + 1;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.list);

        // 配列を生成
        ArrayList<String> numbers = new ArrayList<String>();
        for(int i = 0; i < 100; i++){
            numbers.add(Integer.toString(i));
        }
        // 生成した配列をリストの各要素にassign
        setListAdapter(new ArrayAdapter<String>(
            getApplicationContext(),
            R.layout.list_row,
            numbers
        ));
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu)
    {
        boolean result = super.onCreateOptionsMenu(menu);
        menu.add(0, MENU1_ID, Menu.NONE, R.string.menu1);
        return result;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item)
    {
        switch(item.getItemId()){
        case MENU1_ID:
            startActivity(new Intent(this, PrimeNumberActivity.class));
            finish();
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id)
    {
        // リストがクリックされたとき
        super.onListItemClick(l, v, position, id);
        TextView textView = (TextView) findViewById(R.id.result);
        Integer strItem = Integer.valueOf((String) getListAdapter().getItem(position));
        int num = _isPrime(strItem, textView);
        if(num == 0){
            textView.setText("Prime!!");
        }
        else if(num < 0){
            textView.setText("Not Prime!!");
        }
        else{
            String str = Integer.toString(num);
            textView.setText("Not Prime!! It will be divided by '" + str + "'");
        }
    }

    /**
     *_isPrime
     * @param number
     * @return
     */
    private int _isPrime(Integer number, TextView textView)
    {
        if(number < 2){
            return -1;
        }
        for(int i = 2; i < number / 2 + 1; i++){
            textView.setText(Integer.toString(i));
            if(number % i == 0){
                return i;
            }
        }
        return 0;
    }
}

まぁ、ツッコミどころは沢山あるがとりあえず。

/res/layout/list.xml

上述のActivityのレイアウトを定義する。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView
    android:id="@+id/result"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/msg_title_select"
    android:textSize="16dip"
    />
<ListView
    android:id="@id/android:list"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    />
<TextView
    android:id="@+id/android:empty"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/msg_title_select"
    android:textSize="20dip"
    />
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:id="@+id/buttons"
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        >
    </LinearLayout>
</LinearLayout>

/res/layout/list_row.xml

ListActivityを使用した場合はリストの行のレイアウトを定義する必要がある。文字が小さいとリストが選択しにくいので大きめサイズだ~

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="center"
    android:textSize="24dip"
    android:text="@string/msg_title_select"
    />

■/res/values/strings.xml

多言語対応できるように文字は以下のファイルに記述するべきだ。

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">prime number</string>
    <string name="app_name_list">prime number list</string>
    <string name="msg_title_input">Input a number!</string>
    <string name="msg_title_select">Select a number!</string>
    <string name="button_validate">Validate</string>
    <string name="result_prime">Prime!</string>
    <string name="result_notprime">Not Prime!</string>
    <string name="menu1">Input</string>
    <string name="menu2">List</string>
</resources>

今回はコードにも書いちゃってるけど気にしない♪

■/res/layout/main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
<TextView
    android:id="@+id/result"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:text="@string/msg_title_input"
    android:textSize="16dip"
    />
    <LinearLayout
        android:orientation="vertical"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="bottom"
        >
    <EditText
        android:id="@+id/number"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:paddingBottom="10dip"
        android:inputType="number"
        android:textSize="26dip"
        android:maxLength="7"
        />
    <Button
        android:id="@+id/button_validate"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:text="@string/button_validate"
        />
    </LinearLayout>
</LinearLayout>

Activityは画面だ★

CentOSにSubversionをインストールする

■インストール

yumでサクッとインストールだ!

yum install subversion

■リポジトリの作成

以下のようにするとhogeディレクトリが生成される。

mkdir -p /home/svn/repos/
cd /home/svn/repos/
mkdir hoge
svnadmin create hoge

adminユーザでコミットするなら以下のようにしておく。。。

chown -R admin:admin hoge
chmod -R 0700 hoge

複数ユーザがコミットするときはグループとかで管理しないとなー

androidでActivityを複数使う

ActivityはAndroidManifest.xmlに登録しないと使えない。

<activity android:name=".PrimeNumberActivity"
          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=".PrimeNumberListActivity"
          android:label="@string/app_name_list">
</activity>

androidでListActivityを使う

以下のようにidにはandroid:を付加しないとエラーになる。

<ListView
    android:id="@id/android:list"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    />
<TextView
    android:id="@+id/android:empty"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    />

androidアプリケーションを配布する

android marketでアプリケーションを配布するには署名などの作業が必要となる。

■自己署名の証明書作成

以下のようにkeytoolを使用する。

C:\Program Files\Java\jdk[version]\bin>keytool -genkey -keystore hoge.keystore -
alias hoge -validity 1000

以下のように任意のパスワードの入力を求められる。

キーストアのパスワードを入力してください:
新規パスワードを再入力してください:

正しく自分の名前を入力しよう。

姓名を入力してください。
  [Unknown]:  Taro Hoge

組織単位名の入力だ。

組織単位名を入力してください。
  [Unknown]:  personal

組織名の入力だ。

組織名を入力してください。
  [Unknown]:  personal

都市名の入力だ。

都市名または地域名を入力してください。
  [Unknown]:  Kawasaki

県名の入力だ。

州名または地方名を入力してください。
  [Unknown]:  Kanagawa

国名の入力だ。

この単位に該当する 2 文字の国番号を入力してください。
  [Unknown]:  jp

最後に確認。

CN=Taro Hoge, OU=personal, O=personal, L=Kawasaki, ST=Kanagawa, C=jp で
よろしいですか?
  [no]:  yes

以上で証明書が作成される。

■アプリケーションパッケージへの署名

以下のようにjarsignerを使用する。

cd C:\Program Files\Java\jdk[version]\bin
jarsigner -verbose -keystore hoge.keystore C:\[eclipse-work-space-path]\workspace\PrimeNumber\bin\PrimeNumber.apk hoge

■apkファイルの最適化

以下のコマンドでapkファイルを最適化できる。

cd C:\android-sdk-windows\tools\
zipalign -v 4 C:\[eclipse-work-space-path]\workspace\PrimeNumber\bin\PrimeNumber.apk C:\[eclipse-work-space-path]\workspace\PrimeNumber\bin\output.apk

アップロードするのは新しく生成されたoutput.apkである。

■アップロード

以下から行う。ユーザアカウントの開設は有料($25)である。

http://market.android.com/publish/Home

contentEditableをJavaScriptで変更する際に気をつける事

■結論

以下のように書けばブラウザに関係なく変更が可能である。

document.getElementById('editor').contentEditable = true;//firefox, chrome, opera, safari, IE...OK

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

$('div#editor').attr('contentEditable', true);//firefox, chrome, opera, safari, IE...OK

■失敗例

以下のように書くとIEでは動作しなくなる。

$('div#editor').attr('contenteditable', true);//firefox, chrome, opera, safari...OK