ラベル php の投稿を表示しています。 すべての投稿を表示
ラベル php の投稿を表示しています。 すべての投稿を表示

2015年10月23日金曜日

phpはThreadセーフみたい

php -v
PHP 5.4.42 (cli) (built: Jul 1 2015 22:46:17) Copyright (c) 1997-2014 The PHP Group Zend Engine v2.4.0, Copyright (c) 1998-2014 Zend Technologies
php -i | grep -i "thread"
Thread Safety => enabled

今はphpはthreadセーフなのか。。。
てことはApacheのmpmは何でもいいですね。

2015年9月13日日曜日

PHPでApacheを使う時のパラメータチューニングとメモ

ApacheのMPMは、どちらを選択するべきか?
  • mod_phpは非スレッドセーフ
  • prefork MPM
    リクエストごとにプロセスを生成し、処理が終わればそのプロセスが死ぬ。
  • worker MPM
    リクエストごとにスレッドを生成する。
    スレッドセーフでないApacheモジュールがあるとバグる
phpを使う時はperforkを使う必要がある。
Apache2.4からはdefaultのmpmがeventのため、コンパイル時には気をつける必要がある。
./configure \
--prefix=/usr/local/apache2.4.12 \
--enable-so \
--enable-ssl \
--enable-mods-shared=all \
--with-expat=builtin \
--with-included-apr \
--enable-proxy \
--enable-proxy-http \
--enable-proxy-ajp \
--with-mpm=prefork \
--enable-rewrite

httpd.confの中身

    StartServers             5
    MinSpareServers         10
    MaxSpareServers         30
    MaxRequestWorkers       1000
    ServerLimit             1000
    MaxConnectionsPerChild  30000

StartServers:最初に起動する子プロセスの数
MinSpareServers: 待機する子プロセスの最小数
MaxSpareServers: 待機する子プロセスの最大数
MaxRequestWorkers: スタート時に許される子プロセスの最大数
ServerLimit: MaxRequestWorkersに上限値をつける
MaxRequestsPerChild: それぞれの子プロセスが扱うリクエスト数の制限数

Apache2.4からMaxClientsという名前がMaxRequestWorkersに変更になりました。
httpdのMPMを確認
httpd -V

2012年3月19日月曜日

PHPのsessionをDBに保存する。その参

php5.4から実装されたSessionHandlerInterfaceを使って
sessionをDBに保存しました。
適当にさわったり、ブラウザを落としてみて動作を確認してみて下さい。
Session.php
<?php 
ini_set('session.gc_maxlifetime', 100);
ini_set('session.gc_probability', 100);
ini_set('session.gc_divisor', 100);
session_set_cookie_params(100);

class Session implements SessionHandlerInterface
{
 private $_db;
 private $_fp;

 public function __construct(){
  try{
   $this->_fp = fopen("log.txt", "a+");
   fwrite($this->_fp, "construct: "."\n");
   $this->_db = mysql_connect('localhost', 'root', '');
   $db_selected = mysql_select_db('development');
   if(!$db_selected){
    throw new Exception("SQLException DBの接続に失敗しました"); 
   }
   if(isset($_COOKIE["PHPSESSID"])){
    session_id($_COOKIE["PHPSESSID"]);
   }
  }catch(Exception $e){
   fwrite($this->_fp, $e->getMessage()."\n");
   throw $e;
  }
 }
 public function open($save_path, $session_id)
 {
  fwrite($this->_fp, "open: "."\n");
     return true;
 }
  
 public function read($session_id)
 {
  try{
   $session_id = mysql_real_escape_string($session_id);
   $select_data = "SELECT data "
       . "FROM sessions "
       . "WHERE session_id = '" . $session_id . "'";
   fwrite($this->_fp, "read: " . $select_data . "\n");
   $result = mysql_query($select_data);
   if(!$result){
    throw new Exception("SQLException dataの取得に失敗しました");
   }
   $row = mysql_fetch_row($result);

   return $row[0];

  }catch(Exception $e){
   fwrite($this->_fp, $e->getMessage()."\n");
   throw $e;
  }
 }

 public function write($session_id, $session_data)
 {
  try{
   $count_sessions = "SELECT COUNT(*) FROM sessions WHERE session_id= '" . $session_id . "'";
   $result = mysql_query($count_sessions);
   if(!$result){
    throw new Exception("SQLException dataのカウントに失敗しました");
   }
   $row = mysql_fetch_row($result);
   $count = intval($row[0]);
   if($count > 0){
    $update_sessions = "UPDATE sessions "
           . "SET data='" . $session_data . "',"
           . "updated_at = now() "
           . "WHERE session_id = '" . $session_id . "'";
       fwrite($this->_fp, "write: " . $update_sessions . "\n");
    $result = mysql_query($update_sessions);
    if(!$result){
     throw new Exception("SQLException dataの更新に失敗しました");
    }
   
   }else{
    $insert_sessions  = "INSERT INTO sessions(session_id, "
              . " data," 
              . " created_at)"
                                       . "VALUES(" 
              . "'" . $session_id . "',"
              . "'" . $session_data . "',"
              . " now())";
       fwrite($this->_fp, "write: " . $insert_sessions . "\n");
    $result = mysql_query($insert_sessions);
    if(!$result){
     throw new Exception("SQLException dataの登録に失敗しました");
    }
   }
  }catch(Exception $e){
   fwrite($this->_fp, $e->getMessage()."\n");
   throw $e;
  }
  return true;
 }
 public function close()
 {
  fwrite($this->_fp, "close: "."\n");
     mysql_close($this->_db);

  return true;
 }

 public function destroy($session_id)
 {
  try{
   $session_id = mysql_real_escape_string($session_id);
   $delete_sessions = "DELETE FROM sessions WHERE session_id = '" . $session_id . "'";
   fwrite($this->_fp, "destroy: " . $delete_sessions . "\n");
   $result = mysql_query($delete_sessions);
   if(!$result){
    throw new Exception("SQLException sessionsの削除に失敗しました");
   }
  }catch(Exception $e){
   fwrite($this->_fp, $e->getMessage()."\n");
   throw $e;
  }
  
  return true;
 }

 public function gc($maxlifetime)
 {
  try{
   $gc_sessions  = "DELETE "
                    . "FROM sessions "
              . "WHERE updated_at < current_timestamp + '-" . $maxlifetime . " secs' "
        . " OR (created_at < current_timestamp + '-" . $maxlifetime . " secs' AND updated_at IS NULL)";
   fwrite($this->_fp, "gc: " . $gc_sessions . "\n");
   $result = mysql_query($gc_sessions); 
   if(!$result){
    throw new Exception("SQLException gcに失敗しました"); 
   }
  }catch(Exception $e){
   fwrite($this->_fp, $e->getMessage()."\n");
   throw $e;
  }

  return true;
 }
}
db_test.php
<?php
require_once 'Session.php';
try{
 $handler = new Session();
 session_set_save_handler($handler, true);
 session_start();
 $_SESSION["box"] = "test";
 var_dump($_SESSION);
}catch(Exception $e){
 echo $e->getMessage();
}
db_test2.php
<?php
try{
   require_once 'Session.php';
   $handler = new Session();
   session_set_save_handler($handler, true);
   session_start();
   $_SESSION["box"] = "box";
   var_dump($_SESSION);
   session_destroy();
}catch(Exception $e){
 echo $e->getMessage();
}

2012年3月11日日曜日

PHPのsessionをDBに保存する。その弐

実際にアクセスして動作を確認します。

  1. db_test.phpにアクセスした場合。
    read、gc、writeが動作します。DBにも値が入っています。
    Cookieに保存されているsessionの保存期間は100秒です。
  2. 次にブラウザを落とさずに、そのままdb_test2.phpにアクセスします。
    read、gc、destroyが動作します。
    readはsessionの読み込み時に動きます。

gcはsession_start時に指定した確率で動きます。
session_destroy時にdestroyが動きます。

session_set_cookie_params(100)を指定しない場合の動作はどうなるでしょう?
  1. db_test.phpにアクセスした場合。
    read、gc、writeが動作します。DBにも値が入っています。
    次にブラウザを落とします。必ずプロセスもkillして下さい。
  2. そして再度、ブラウザを立ち上げてdb_test2.phpにアクセスします。
    sessionの中身が空になっていることが確認できます。
    しかしDBにはsessionのデータが残っています。
    これはいつ削除されるのでしょうか?
    それは次に、どちらかのファイルにアクセスがあった際にgc関数によって削除されます。
以上で実装したかったことを実装できたと思います。
次回はphp5.4の場合について実装してみたいです。

PHPのsessionをDBに保存する。その壱

実装したいこと。
  • phpのsessionをDBに保存する。
  • sessionに期限を持たせて使いたい。cookieと同様の使い方。
  • DBに保存されたdataを定期的に削除したい。
  • phpのバージョンは5.3以下
document rootが/var/www/html
その下にsessiontestを作成。その中に以下のファイルを作成。
DBSession.php  db_test.php  db_test2.php  log.txt
tableの作成
CREATE TABLE `sessions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `session_id` char(32) NOT NULL,
  `data` text,
  `created_at` datetime DEFAULT NULL,
  `updated_at` datetime DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_session_id` (`session_id`),
  KEY `idx_created_at` (`created_at`),
  KEY `idx_updated_at` (`updated_at`)
) 
DBSession.php
session.save_handler
sessionの保存先をユーザー定義に変更。
session_set_save_handlerでユーザー定義関数を指定。
名前は何でもいいですけど、わかりやすい名前がいいです。
session.gc_maxlifetime
第6引数、下記の例だとgc関数に渡される引数の時間を指定します。
ここでは100秒を指定。
gcが動く確率は gc_probability/gc_divisorで設定されます。
今回は100%動かしたいので100/100*100=100%に設定しました。
session_set_cookie_paramsには100秒を指定しました。
これでブラウザを落としても、sessionが有効になっています。
少し微妙な言い回しですけど。

<?php

    ini_set('session.save_handler', 'user');

    ini_set('session.gc_maxlifetime', 100);

    ini_set('session.gc_probability', 100);

    ini_set('session.gc_divisor', 100);



    session_set_save_handler('open', 'close', 'read', 'write', 'destroy', 'gc');

    session_set_cookie_params(100);



    define('HOST', "localhost");

    define('USER', "root");

    define('PASSWORD', "");

    define('DATABASE', "development");

    if(isset($_COOKIE["PHPSESSID"])){

        session_id($_COOKIE["PHPSESSID"]);

    }



    function open(){

        return true;

    }



    function close(){

        return true;

    }



    function read($session_id){

        $rtn = "";

        $db = new mysqli(HOST, USER, PASSWORD, DATABASE);



        $session_id = mysql_real_escape_string($session_id);



        $select_data  = "SELECT data "

                      . "FROM sessions "

                      . "WHERE session_id = '" . $session_id . "'";

        $fp = fopen("log.txt", "a+");

        fwrite($fp, "read: " . $select_data . "\n");



        $rs = $db->query($select_data);

        if($rs){

            while ($row = $rs->fetch_assoc()) {

                $rtn = $row['data'];

            }

        }


   function write($session_id, $data){

        $rtn = false;

        $db = new mysqli(HOST, USER, PASSWORD, DATABASE);

        $session_id = mysql_real_escape_string($session_id);

        $data = mysql_real_escape_string($data);



        $select_sessions = "SELECT * FROM sessions WHERE session_id='" . $session_id . "'";

        $fp = fopen("/var/www/html/sessiontest/log.txt", "a+");

        fwrite($fp, "write: " . $select_sessions . "\n");

        $rs = $db->query($select_sessions);

        if($rs->fetch_row() > 0){

            $update_sessions  = "UPDATE sessions "

                               . "SET data = '" . $data . "',"

                               . "updated_at =  NOW() "

                               . "WHERE session_id = '" . $session_id . "'";

            $rs = $db->query($update_sessions);

        }else{

            $insert_sessions  = "INSERT INTO sessions(session_id, data, created_at)"

                                 . "VALUES('" . $session_id . "','" . $data . "',NOW())";

            $rs = $db->query($insert_sessions);

            var_dump($rs);

        }



        $rtn = true;



        return $rtn;

    }




        return $rtn;

      }


 function destroy($session_id){

        $db = new mysqli(HOST, USER, PASSWORD, DATABASE);

        $delete_sessions = "DELETE FROM sessions WHERE session_id = '" . $session_id . "'";

        $fp = fopen("/var/www/html/sessiontest/log.txt", "a+");

        fwrite($fp, "destroy: " . $delete_sessions . "\n");

        $db->query($delete_sessions);



        return true;

    }



    function gc($maxlifetime){

        $rtn = false;

        $db = new mysqli(HOST, USER, PASSWORD, DATABASE);



        $gc_sessions  = "DELETE "

                           . "FROM sessions "

                           . "WHERE updated_at < current_timestamp + '-" . $maxlifetime . " secs' "

                           . " OR (created_at < current_timestamp + '-" . $maxlifetime . " secs' AND updated_at IS NULL)";



        $db->query($gc_sessions);

        $fp = fopen("/var/www/html/sessiontest/log.txt", "a+");

        fwrite($fp, "gc: " . $gc_sessions . "\n");



        $rtn = true;



        return $rtn;



    }

db_test.php
<?php
require_once 'DBSession.php';
session_start();
$_SESSION["box"] = "test";
var_dump($_SESSION);

db_test2.php
<?php
  require_once 'DBSession.php';
  session_start();
  var_dump($_SESSION);
  session_destroy();