Symfoware

Symfowareについての考察blog

CodeIgniter 3 自分で作成したモデルを継承する

CodeIgniter 3でCI_Modelを継承しモデルを定義。

・Base_model


  1. <?php
  2. // Base_modelを継承したモデル
  3. // Controllerからはこれを使用したい
  4. class Ext_model extends Base_model {
  5.     
  6.     public function say() {
  7.         echo 'Ext_model'.PHP_EOL;
  8.     }
  9.     
  10. }




このモデルを再度継承して拡張モデルを定義したい。

・Ext_model


  1. <?php
  2. // CI_Modelを継承したモデル
  3. // これを継承元としたい
  4. class Base_model extends CI_Model {
  5.     
  6.     public function say() {
  7.         echo 'Base_model'.PHP_EOL;
  8.     }
  9.     
  10. }




この状態で使用するとエラーになります。

・Test.php


  1. <?php
  2. class Test extends CI_Controller {
  3.     
  4.     // 作成した継承モデルの呼び出し
  5.     public function index() {
  6.         
  7.         $this->load->model('ext_model');
  8.         $this->ext_model->say();
  9.         
  10.     }
  11.     
  12. }





# php index.php test
PHP Fatal error: Class 'Base_model' not found in /var/dev/php/ci3/application/models/Ext_model.php on line 5

Fatal error: Class 'Base_model' not found in /var/dev/php/ci3/application/models/Ext_model.php on line 5

A PHP Error was encountered

Severity:    Error
Message:     Class 'Base_model' not found
Filename:    /var/dev/php/ci3/application/models/Ext_model.php
Line Number: 5

Backtrace:




まあ、Base_modelがロードされていないので当然なのですが。





解決策1



Base_modelがロードされていないことが原因なので、事前にロードしてやります。


  1. <?php
  2. class Test extends CI_Controller {
  3.     
  4.     // 作成した継承モデルの呼び出し
  5.     public function index() {
  6.         
  7.         // 事前にbase_modelをロード
  8.         $this->load->model('base_model');
  9.         $this->load->model('ext_model');
  10.         $this->ext_model->say();
  11.         
  12.     }
  13.     
  14. }




# php index.php test
Ext_model




動くには動きますし、modelのautoloadに指定してしまえば良いのですが、
あんまりしっくりきません。





解決策2



解決策1と似たような発想で、Ext_modelにBase_modelがロード済みか
チェックするロジックを入れてしまいます。

・Ext_model


  1. <?php
  2. // Base_modelを継承したモデル
  3. // Controllerからはこれを使用したい
  4. // 事前にBase_modelがロード済みかチェック
  5. if (!class_exists('Base_model')) {
  6.     // 未ロードならロード
  7.     get_instance()->load->model('base_model');
  8. }
  9. class Ext_model extends Base_model {
  10.     
  11.     public function say() {
  12.         echo 'Ext_model'.PHP_EOL;
  13.     }
  14.     
  15. }




これで呼び出せるようになりました。


  1. <?php
  2. class Test extends CI_Controller {
  3.     
  4.     // 作成した継承モデルの呼び出し
  5.     public function index() {
  6.         
  7.         $this->load->model('ext_model');
  8.         $this->ext_model->say();
  9.         
  10.     }
  11.     
  12. }




# php index.php test
Ext_model







解決策3



Hookとspl_autoload_registerの組み合わせを試してみます。

CodeIgniter 3 処理のフック(General Topics - Hooks - Extending the Framework Core)
PHP spl_autoload_registerでautoloadを自前で実装


※以下、例外処理のない適当な実装です。

まずHookを有効化。
application/config/config.phpのenable_hooksをtrueにします。


  1. /*
  2. |--------------------------------------------------------------------------
  3. | Enable/Disable System Hooks
  4. |--------------------------------------------------------------------------
  5. |
  6. | If you would like to use the 'hooks' feature you must enable it by
  7. | setting this variable to TRUE (boolean). See the user guide for details.
  8. |
  9. */
  10. $config['enable_hooks'] = TRUE;




application/config/hooks.phpを編集
pre_systemでspl_autoload_registerを登録します。


  1. <?php
  2. defined('BASEPATH') OR exit('No direct script access allowed');
  3. /*
  4. | -------------------------------------------------------------------------
  5. | Hooks
  6. | -------------------------------------------------------------------------
  7. | This file lets you define "hooks" to extend CI without hacking the core
  8. | files. Please see the user guide for info:
  9. |
  10. |    https://codeigniter.com/user_guide/general/hooks.html
  11. |
  12. */
  13. $hook['pre_system'][] = spl_autoload_register(function($className) {
  14.     // Base_modelの解決
  15.     get_instance()->load->model($className);
  16. });




これで動いてくれました。



わかりやすさから、解決策2のモデルクラスの先頭でチェックするのが良さそうでした。



関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/02/14(火) 00:02:13|
  2. PHP
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

Python webサーバー、フレームワークを使用せずにwebアプリ作成

個人的なツール用として簡単なwebアプリを作成したかったのですが、
なんとか素のPythonだけで実装できないか考えてみました。


BaseHTTPServer,SimpleHTTPServer



Python 2系の場合、BaseHTTPServerが標準で組み込まれています。
※Python 3系ではhttp.server

これらを使用すれば良さそうです。

作成するwebアプリでは、htmlやjsファイルは通常通りget。
javascriptからのデータ取得はPOSTのみで行うことにし、
実装を簡単にしました。



POSTデータの解析



POSTデータの解析をどうやれば良いかわからず探したところ、
このドキュメントが参考になりました。

BaseHTTPServer – web サーバを実装するベースクラス

cgi.FieldStorageを使用すれば解析できそうです。



サンプルアプリケーション



アプリケーションは
・index.html
・app.js
・view.py
の3つのファイルで構成しました。

名前を入力すると、応答してくれる簡単なものです。

731_01.png


・index.html


  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>Simple Web</title>
  6.     <script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
  7.     <script type="text/javascript" src="./static/js/app.js"></script>
  8. </head>
  9. <body>
  10. <h3>Pythonのみで簡易Webアプリ</h3>
  11. <input type="text" id="name">
  12. <input type="button" id="echo" value="ajaxでデータ取得">
  13. <div id="result"></div>
  14. </body>
  15. </html>




・app.js


  1. $(function() {
  2.     
  3.     // 入力された値をPOSTで送信
  4.     // 応答を表示する
  5.     $('#echo').on('click', function(){
  6.         var name = $('#name').val();
  7.         $.ajax({
  8.             type: 'POST',
  9.             dataType: 'json',
  10.             data: {'name':name},
  11.             url: 'echo',
  12.         }).done(function (data) {
  13.             $('#result').html(data.message);
  14.         });
  15.     });
  16.     
  17. });




・view.py


  1. # -*- coding: utf-8 -*-
  2. import cgi
  3. import json
  4. import BaseHTTPServer
  5. import SimpleHTTPServer
  6. class MyHandler(SimpleHTTPServer.SimpleHTTPRequestHandler):
  7.     
  8.     # POSTの実装(GETは継承元にある)
  9.     def do_POST(self):
  10.         
  11.         # リクエストに対応したメソッドを呼び出す
  12.         route = self.path.split('/')[-1]
  13.         if not hasattr(self, route):
  14.             self.send_response(500)
  15.             self.end_headers()
  16.             return
  17.         
  18.         # POSTデータの解析
  19.         form = self._parse_form()
  20.         response = getattr(self, route)(form)
  21.         
  22.         # レスポンス作成
  23.         self.send_response(200)
  24.         self.send_header("Content-type", 'application/json')
  25.         self.send_header("Content-Length", len(response))
  26.         self.end_headers()
  27.         self.wfile.write(response)
  28.         
  29.         
  30.     def _parse_form(self):
  31.         if 'Content-Type' not in self.headers:
  32.             return None
  33.         
  34.         # POSTデータがあれば内容を解析する
  35.         return cgi.FieldStorage(
  36.             fp=self.rfile,
  37.             headers=self.headers,
  38.             environ={
  39.                 'REQUEST_METHOD':'POST',
  40.                 'CONTENT_TYPE':self.headers['Content-Type'],
  41.             }
  42.         )
  43.     
  44.         
  45.         
  46.     # --- router
  47.     def echo(self, form):
  48.         
  49.         name = u'名無し'
  50.         
  51.         # データが送信されていれば、内容を応答
  52.         if 'name' in form:
  53.             name = form['name'].value
  54.         
  55.         message = u'%sさんこんにちは' % name
  56.         data = {'message' : message}
  57.         return json.dumps(data)
  58.     
  59.     
  60. if __name__ == '__main__':
  61.     
  62.     server_address = ('0.0.0.0', 8000)
  63.     httpd = BaseHTTPServer.HTTPServer(server_address, MyHandler)
  64.     print('Serving HTTP on 0.0.0.0 port %d ...' % server_address[1])
  65.     print('use <Ctrl-(C or break)> to stop')
  66.     httpd.serve_forever()
  67.     





$ python view.py

と実行して、http://localhost:8000にアクセスします。

731_02.png


適当な文字列を入力してボタンをクリックすると、応答が得られました。

731_03.png


なんとかPython単独でwebアプリケーションが作成できそうです。



【参考URL】

SimpleHTTPServer — 簡潔な HTTP リクエストハンドラ
BaseHTTPServer – web サーバを実装するベースクラス
関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/01/30(月) 23:53:09|
  2. Python
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

HTML5 canvasで画像の矩形選択(clip)

画像の一部を矩形で範囲選択したく、Jcropを使おうとしたのですが、
開発も滞っており、jQueryの最新版(3系)では動きませんでした。

せっかくなので、jQueryプラグインを使用せず、
HTML5 canvasだけで実装できるか試してみます。


やりたいこと



こんな感じで、画像の一部をマウス操作で矩形選択したい。
730_01.png

※ネコの画像はこちらから引用しています。
Pixabay


こちらを参考にさせていただきました。
HTML5 canvasを使った矩形選択と選択範囲塗りつぶし


作成したサンプルはこちら。
rect select

ソースはこんな感じになります。


  1. <!DOCTYPE html>
  2. <html lang="ja">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>rect select</title>
  6. <script type="text/javascript">
  7. window.onload = function() {
  8.     var canvas = document.getElementById('drowing');
  9.     var context = canvas.getContext('2d');
  10.     var reacts = [];
  11.     
  12.     var imageObj = new Image();
  13.     imageObj.onload = function() {
  14.         canvas.width = imageObj.width;
  15.         canvas.height = imageObj.height;
  16.         draw();
  17.     };
  18.     imageObj.src = 'sample2_image.jpg';
  19.     
  20.     canvas.addEventListener("mousedown", onMouseDown, false);
  21.     canvas.addEventListener("mouseup" , onMouseUp , false);
  22.     window.addEventListener("keyup" , onKeyUp , false);
  23.     
  24.     // 矩形オブジェクト
  25.     var _rectangle = createRect();
  26.     
  27.     function createRect() {
  28.         return { startY:0, startX:0, endY:0, endX:0 };
  29.     };
  30.     
  31.     function onMouseDown (e) {
  32.         _rectangle.startY = e.clientY;
  33.         _rectangle.startX = e.clientX;
  34.         canvas.addEventListener ("mousemove", onMouseMove, false);
  35.     };
  36.     function onMouseMove (e) {
  37.         draw();
  38.         _rectangle.endY = e.layerY - _rectangle.startY;
  39.         _rectangle.endX = e.layerX - _rectangle.startX;
  40.         context.lineWidth = 5;
  41.         context.strokeStyle = "rgb(255, 0, 0)";
  42.         context.strokeRect (_rectangle.startX, _rectangle.startY, _rectangle.endX, _rectangle.endY);
  43.     };
  44.     function onMouseUp (e) {
  45.         reacts.push(_rectangle);
  46.         draw();
  47.         _rectangle = createRect();
  48.         canvas.removeEventListener ("mousemove", onMouseMove, false);
  49.     };
  50.     
  51.     function draw() {
  52.         context.drawImage(imageObj, 0, 0);
  53.         context.lineWidth = 5;
  54.         context.strokeStyle = "rgb(255, 0, 0)";
  55.         reacts.forEach(function(rect) {
  56.             context.strokeRect(rect.startX, rect.startY, rect.endX, rect.endY);
  57.         });
  58.     };
  59.     
  60.     function onKeyUp (e) {
  61.         switch(e.key) {
  62.             case 'z':
  63.                 reacts.pop();
  64.                 break;
  65.             default:
  66.                 return;
  67.         };
  68.         draw();
  69.     };
  70.     
  71. };
  72. </script>
  73.     
  74. </head>
  75. <body>
  76.     <div class="main">
  77.         <canvas id="drowing" class="drowing" width="0" height="0"></canvas>
  78.     </div>
  79.     <div>
  80.         <div>zキーで最新の矩形を削除</div>
  81.     </div>
  82. </body>
  83. </html>




canvasを二枚重ねても良かったのですが、制御が面倒だったので
毎回背景画像を描画しなおしてから、矩形を重ねています。

シビアな性能が求められる場合は一考の余地ありですが、
とりあえずの実装であればこれで十分そうです。
関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/01/26(木) 23:33:47|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

Python Windows で serve_foreverの実行がCtrl + Cで停止しない

例えばこんなプログラム。


  1. # -*- coding:utf-8 -*-
  2. import BaseHTTPServer
  3. import SimpleHTTPServer
  4. server_address = ('', 8000)
  5. handler = SimpleHTTPServer.SimpleHTTPRequestHandler
  6. httpd = BaseHTTPServer.HTTPServer(server_address, handler)
  7. httpd.serve_forever()




実行後、ブラウザで「http://localhost:8000/」にアクセスすると、
実行しているディレクトリの内容が表示されます。


Windowsで実行時、プログラムをCtrl + Cで停止しようとしても止まってくれない。

Stopping python using ctrl+c

ここを参考に、Ctrl + Breakで停止できました。


関連記事

テーマ:プログラミング - ジャンル:コンピュータ

  1. 2017/01/26(木) 00:01:36|
  2. Python
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集

avconv jpg画像と音声ファイルから動画(mp4)を作成

avconv(ffmpeg)を使用して、動画から画像ファイル(jpg)と音声ファイル(aac,mp3)を抽出しました。
avconv(ffmpeg)でmp4の動画ファイルからjpg形式で画像を取り出す
avconv(ffmpeg) 動画ファイルから音声ファイルのみ抽出(aac,mp3)

出力した画像・音声を合成し、再度動画ファイルを作成してみます。





画像・音声の分割



復習として、画像と音声ファイルの抽出を行います。

・画像

target.mp4という動画ファイルからjpg画像を連番で出力


# avconv -i target.mp4 -vsync 1 -r 25 -an -y -qscale 1 image/out_%04d.jpg




1分程度の動画ファイルから1,715枚のjpg画像が抽出出来ました。



・音声

aac形式で音声ファイルを抽出します。


# avconv -i target.mp4 -c:a copy -vn -y out.aac




これで、imageフォルダに動画ファイルから抽出した画像、
out.aacに音声ファイルが取得できました。






動画・音声の結合



まず、画像を結合してmov形式の動画ファイルを作成します。


# avconv -framerate 25 -f image2 -i image/out_%04d.jpg -c:v h264 -crf 1 no_sound.mov




これで音声の入っていない動画ファイル「no_sound.mov」ができました。
これに音声を付与しつつ、mp4形式に変換します。


# avconv -i no_sound.mov -i out.aac -c:v libx264 -strict experimental result.mp4




ここで、「-strict experimental」オプションを指定していないと、

encoder 'aac' is experimental and might produce bad results.
Add '-strict experimental' if you want to use it.

というエラーが発生します。


この手順で、「result.mp4」という動画ファイルに復元できました。
※ファイルサイズは大きくなってしまいましたが。





【参考URL】

Snippets avconv
avconv Documentation
Convert from .mov to .mp4 (or h264) using avconv
avconvコマンドでtsファイルを分割(split)
Unixでwmvファイルを他のファイルフォーマットに変換したい
関連記事

テーマ:サーバ - ジャンル:コンピュータ

  1. 2017/01/25(水) 00:33:29|
  2. 備忘録
  3. | トラックバック:0
  4. | コメント:0
  5. | 編集
次のページ