狛ログ

2015年1月20日火曜日

Codeigniter 2.1.4 と PHP5.6 でのエラー。

1月 20, 2015
オフィス狛 技術部です。

久しぶりの Codeigniter です。
今回、Codeigniter で作成したシステムをリニューアルする事になり、
PHPのバージョンを上げる事になりました。(PHP5.2→5.6)

早速、PHPのバージョンを上げて、プログラムは一切変えずに実行してみたところ・・・

A PHP Error was encountered
Severity: Notice
Message: Only variable references should be returned by reference
Filename: core/Common.php
Line Number: 257

どうやら、フレームワーク(Codeigniter)内部のエラーのようです。
エラー内容で検索すると、下記サイトが出てきました。

修正方法としては、上記サイトを参考に、
return $_config[0] =& $config;
という一文を
$_config[0] =& $config;
return $_config[0];
このように変えるだけです。

ちなみに、Codeigniter のバージョンを調べる方法ですが、

system/core/CodeIgniter.php 」に「 define('CI_VERSION', '2.1.4');
のように定義されています。

※昔のバージョンだと、定義してある箇所が違っているようなので、上記場所に無い場合、
こちら(CodeIgniter のバージョンの調べ方)の記事を参考にして調べた方が良いかもしれません。

覚悟をしていたものの・・・PHPのバージョンを上げるのは一苦労です。

2014年9月7日日曜日

Highcharts JS で Highcharts error #14。

9月 07, 2014
オフィス狛 技術部です。

あるシステムで Highcharts JS を使っているのですが、
新しいグラフを追加する事になり、データ提供元のWebAPIを利用しJSONを取得して表示したところ、
以下のエラーになりました。
Highcharts error #14: www.highcharts.com/errors/14

軸のデータが変わっただけで、グラフ表示形式も、JSON形式も他のグラフと違いないはず・・・
とりあえず、エラーメッセージには親切にもURLが付いているのでアクセスしてみます。

String value sent to series.data, expected Number
This happens if you pass in a string as a data point, for example in a setup like this:
series: [{
data: ["3", "5", "1", "6"]
}]
Highcharts expects the data values to be numbers. The most common reason for this is that data is parsed from CSV or from a XML source, and the implementer forgot to run parseFloat on the parsed value. For performance reasons internal type casting is not performed, and only the first value is checked (since 2.3).

読み解くと、x、y軸に表示するデータは、数値扱いにしなければならない。
という事のようです。
上記の例だと、
 series: [{
     data: [3, 5, 1, 6]
 }]
このようにダブルクォーテーションを取る・・・という事ですね。

実は今回のWebAPIも弊社が作成しているので、WebAPI側を修正する事が出来ました。
逆に言うと、他社のWebAPIを利用する場合に、こんな現象に遭遇したら・・・嫌ですね。

2014年8月10日日曜日

ASP.net EnterキーでのSubmit(ポストバック)制御。

8月 10, 2014
オフィス狛 技術部です。

Webシステムで、EnterキーでのSubmitを制御したいという要望はよくあります。

色々と方法はありますが、JavaScriptで制御させる方法が多いと思います。

後は、ASP.netのコントロールであるButtonコントロールを使わず、htmlタグのbuttonタグを使う方法や、
ダミーボタンを用意し、FormのDefaultButtonに設定する、などです。

※ダミーボタンを作成する際は、ButtonコントロールのプロパティであるVibibleをFalseにしてはいけません。
VibibleがFalseになっているコントロールは、htmlに変換する際に対象外となるからです。


ただ、そのような要望が、開発の終盤に出てくると、修正も大変ですよね。

ASP.netを利用しているのであれば、Site.Masterに以下のような記載をすると、修正が1か所で済みます。
<div id="body">
    <asp:Panel ID="PanelDummy" runat="server" DefaultButton="ButtonDefault">
    <asp:ContentPlaceHolder runat="server" ID="FeaturedContent" />
    <asp:ContentPlaceHolder runat="server" ID="MainContent" />
    <asp:Button ID="ButtonDefault" runat="server" Text="" Width="0" Height="0" OnClientClick="return false;" style="visibility:hidden;" />
    </asp:Panel>
</div>
ContentPlaceHolderの部分は各画面で置き換えられるコンテンツ部分ですが、
そのコンテンツ部分をPanelコントロールで括っています。
そして、そのPanelにはデフォルトボタンが設定されていて、
そのボタンは OnClientClick="return false;" でSubmiteを無効にしています。

非表示についても、ボタンのプロパティではなく、CSSのstlye設定を利用しているところもポイントです。

EnterキーでのSubmit(ポストバック)は、利用する人によって、「必要だ」という意見もあれば、
「不要だ」という意見もあり、現場では正直困ってしまう事もあります・・・・。

2014年7月26日土曜日

CodeIgniterのActiveRecord(where句の動的生成)。

7月 26, 2014
オフィス狛 技術部です。

前々回に引き続き、今回もCodeIgniterのActiveRecordで苦労した事を備忘録として残しておきます。

CodeIgniterのActiveRecordでは、
$this->db->where('item1', '1');
$this->db->where('item2', '2');
上記のように、カラムと検索値を指定するだけで、簡単にwhere句が作成できます。

ただし、複雑なSQL文の事を考慮し、動的にwhere句を作成する事もできます。
// 検索条件の作成
$whereString = ' ( item1 = ' . $value1;
$whereString.= '   or  item1 = ' . $value2 . ')';
$whereString.= ' and del_flg = ' . $delFlg;
$whereString.= ' and proc_date < ' . $nowDate;

$updateData = array(
        'del_flg' => self::NOT_DEL_DATA,
        'last_updated_user' => self::PRG_ID,
        'updated_at' => $updateTime,
);

$this->db->where($whereString);
$this->db->update('sample_table', $updateData);
上記は、変数whereStringにwhere句を動的作成して格納していますが、
実はエラーになってしまいます。(正しく解析されない)

原因は、whereStringの先頭に半角スペースが設定されている為です。
先頭の半角スペースを削除すれば、正常に動作します。

修正したものは以下になります。
(半角スペースだけの問題なので、パッと見は変わりませんが)
// 検索条件の作成
$whereString = '( item1 = ' . $value1;
$whereString.= '   or  item1 = ' . $value2 . ')';
$whereString.= ' and del_flg = ' . $delFlg;
$whereString.= ' and proc_date < ' . $nowDate;

$updateData = array(
        'del_flg' => self::NOT_DEL_DATA,
        'last_updated_user' => self::PRG_ID,
        'updated_at' => $updateTime,
);

$this->db->where($whereString);
$this->db->update('sample_table', $updateData);
これは、原因を突き止めるのに、本当に時間が掛かりました。

2014年7月6日日曜日

Unity で Internal compiler error。

7月 06, 2014
オフィス狛 技術部です。

社内でUnity開発用の端末を追加して、環境設定した後、
プロジェクトをコピーしてビルドしたら以下のメッセージが出ました。
(OSはWindows7 64bit、Unityのバージョンは4.3.4)

Internal compiler error. See the console log for more information. output was:
Unhandled Exception: System.UnauthorizedAccessException: Access to the path "C:\xxxx\yyyy\zzzz\Temp\Assembly-CSharp.dll.mdb" is denied.

他の端末では、何の問題もなくビルド出来ています。
メッセージからすると、何か権限絡みエラーな気がしますが・・・

他の端末とのは違いは、アンチウィルスソフトぐらいしか・・・って、調べてみたら、これが原因でした。

今回の設定した端末のみ、アンチウィルスソフトはMcAfeeをインストールしているのですが、
McAfeeのリアルタイムスキャンがビルドの邪魔をしているようです。

検索したら、同じような現象で困っている人が。


とりあえず、リアルタイムスキャンを止めたら、エラーは解消し、ビルド出来ました。
・・・が、毎回リアルタイムスキャン止めるのも面倒なので、結局アンチウィルスソフト変える事にしました。

2014年6月11日水曜日

CodeIgniterのActiveRecord(SQL関数利用時の別名について)。

6月 11, 2014
オフィス狛 技術部です。

オフィス狛では、PHP開発を行う際は規模によって使用するフレームワークを変えています。

中・大規模の場合は、Symfony2を主に利用し、
Web APIや、簡単なメンテナンス系画面を作成する際は、
軽量フレームワークのCodeIgniterを利用しています。

今回は、CodeIgniterのActiveRecordで、苦労した問題を備忘録として残しておきます。

CodeIgniterのActiveRecordには、関数がいくつか用意されています。

  • select_max(field, alias)
    • クエリの "SELECT MAX(field)" の部分を書き出します。 結果フィールドをリネームするために、追加で第2引数を指定できます。
  • select_min(field, alias)
    • クエリの "SELECT MIN(field)" の部分を書き出します。select_max() と同様に、結果フィールドをリネームするために、追加で第2引数を指定できます。
  • select_avg(field, alias)
    • クエリの"SELECT AVG(field)" の部分を書き出します。 select_max() と同様に、結果フィールドをリネームするために、追加で第2引数を指定できます。
  • select_sum(field, alias)
    • クエリの"SELECT SUM(field)"の部分を書き出します。select_max() と同様に、結果フィールドをリネームするために、追加で第2引数を指定できます。

例えば、select_maxの使い方は以下の通りです。
$keyMaxId = 0;

$selectmax = array(
        'key_id',
        'item_div',
);
$this->db->select_max('key_id', 'maxId');;
$this->db->from('sample_table');
$this->db->where('item_div', $this->config->item('item_div'));
$querymax = $this->db->get();
$productmax = $querymax->row(0, 'object');

if (count($productmax) > 0) {
    $keyMaxId = $productmax->maxId;
    $keyMaxId++
}

return $keyMaxId;
上記は、テーブル(sample_table)のキー(key_id)のMAX値を取得して、
1加算して値を返却する処理ですが、
実は、上記だと実行時エラーになってしまいます。
原因は「select_maxの第2引数のalias(別名)」にあります。

関数の第2引数のalias(別名)は『全て小文字』で設定しないといけません。
上記例で言うと、「maxId」ではなく、「maxid」と記載するのが正解です。

こういった細かいミスは気付き難いです・・・・。

2014年6月10日火曜日

Entity Framework 5におけるデータバインド。

6月 10, 2014
オフィス狛 技術部です。

Entity Framework 4.xを利用しているシステムをリニューアルする事になり、
.NET Frameworkのバージョンを上げ、Entity Framework も 5 にバージョンアップさせました。

その状態で実行すると、

Data binding directly to a store query (DbSet, DbQuery, DbSqlQuery) is not supported Entity Framework 5

というエラーメッセージが表示されました。
日本語環境だと、

ストア クエリ (DbSet、DbQuery、DbSqlQuery) への直接のデータ バインドはサポートされていません。代わりに、DbSet で Load を呼び出すなどして DbSet にデータを設定し、ローカル データにバインドしてください。WPF の場合は DbSet.Local に、WinForms の場合は DbSet.Local.ToBindingList() にバインドします

と表示されました。

元々のプログラムは単純で、
テーブルから取得したデータをドッロプダウンリストにバインドしているだけです。
using (var context = new DeomDbEntities())
{
  var testObject =
      from master in context.code_name
      where master.code_type == '1' &&
            master.delete_flg == '0'
      orderby master.display_order
      select new { code_value = master.code_value, code_text = master.code_text };

  if (testObject != null)
  {
      dropDownList.DataSource = testObject;
      dropDownList.DataValueField = "code_value";
      dropDownList.DataTextField = "code_text";
      dropDownList.DataBind();
  }
}
日本語のエラーメッセージが分かり難かったのですが、
要は「クエリを直接データソースに設定するな」という事だとだと思い、

dropDownList.DataSource = testObject;

上記部分を

dropDownList.DataSource = testObject.ToList();

と変更する事で、エラーメッセージが表示されなくなりました。
ヒントとなる情報は国内サイトでは見つかりませんでしたが、
Stack Overflowで発見しました。
(プログラムでハマってしまった時に検索すると、大抵「Stack Overflow」に行き着きますよね・・・)
修正後のプログラムは以下に記載しておきます。
using (var context = new DeomDbEntities())
{
  var testObject =
      from master in context.code_name
      where master.code_type == '1' &&
            master.delete_flg == '0'
      orderby master.display_order
      select new { code_value = master.code_value, code_text = master.code_text };

  if (testObject != null)
  {
      dropDownList.DataSource = testObject.ToList();
      dropDownList.DataValueField = "code_value";
      dropDownList.DataTextField = "code_text";
      dropDownList.DataBind();
  }
}
余談ですが、Entity Frameworkのバージョンに関する情報は下記サイトが参考になりました。
Entity Framework の歴史を振り返る