CodeIgniter Undefined index: REMOTE_ADDR

在 command line 執行 cli 程式的時候會遇到一個問題

<h4>A PHP Error was encountered</h4>
<p>Severity: Notice</p>
<p>Message: Undefined index: REMOTE_ADDR</p>
<p>Filename: core/Input.php</p>
<p>Line Number: 351</p>

core/Input.php 內有一行程式長這樣

$this->ip_address = $_SERVER[‘REMOTE_ADDR’];

因為 cli 並不會有 REMOTE_ADDR 這種東西
(本地執行哪來的 REMOTE_ADDR)
所以程式就爆炸了

找了一些資料

可以把上面那行換成

if(isset($_SERVER[‘REMOTE_ADDR’]))
$this->ip_address = $_SERVER[‘REMOTE_ADDR’];
else
$this->ip_address = ‘0.0.0.0’;

抓不到 $_SERVER[‘REMOTE_ADDR’] 的時候
就把 ip_address 改成 0.0.0.0 即可

因為很常查這個 所以乾脆就自己寫一篇

[CodeIgniter] character_limiter / word_limiter 切斷過長字元的 function

做首頁的程式套版的時候
很常遇到一種東西

例如最新消息可能 300px
但是客人在後台輸入的很長的標題
結果造成超出版面

以前都是自己寫 function 去把過長的標題切斷
然後加上 ‘….’

後來發現其實這功能 CodeIgniter 早就有這個功能了
(這就是用 framework 的好處)

詳細說明在官網

用法如下(也是從官網copy的)

$string = “Here is a nice text string consisting of eleven words.”;
$string = character_limiter($string, 20);
// Returns: Here is a nice text string…

大概就是這樣的效果
至於 word_limiter 也有類似的功能
只是他可以避免用 character_limiter 去切斷一個完整的英文字

不過有稍微 google 一下
似乎中文字會有問題
因為 function 並沒有考慮到 multi-byte 的字的關係
大概就是用 mb_string 去修改這樣
這邊就不贅述了
僅介紹功能

framwork 的意義其實就是避免自己造輪子
做人家已經做過的事情
而且自己做的也不見得比人家的品質好/有效率
那何不用別人寫好的呢?

[CodeIgniter] Session size 不足?

剛我有史以來最成功的購物網站案例
DressCode 老闆來訊說

他的客人買了30件衣服
但是購物車只有顯示16件
我真的是傻眼了
生意真是好啊

我測試的時候從來也沒想要把30件產品加入到購物車
看會怎麼樣XD
很顯然是 session 爆掉了

其實問題很簡單
因為 session 是放在 cookie 裡面
cookie size 通常是 4k
存一些亂七八糟的東西
很容易就爆掉了

之前部落格有寫一篇
[CodeIgniter] 把 session 寫入db

只要照的做
把 session 改成存在 db 中即可解決問題~

[CodeIgniter] list 不能當 function name 的問題

這個問題其實很簡單
因為 list 這個字是 php 的關鍵字
所以當然不能拿來當 function name

因為 CodeIgniter 的 controller function name 會被拿來當做 url 的一部分
例如

http://example.com/product/list/page3/

product 會是 controller 的 class name
而 list 就會是 function name

可是如同文章標題
list 這個字是不能當 function name 的
但是我又不想把 function name 改成其他字
怎麼辦呢

這時候就要用 CI 強大的 Route 功能囉

此時編輯 config/routes.php
加入這行

$route[‘product/list/(:any)’]          = “product/enum/$1”;

這行的作用是 把網址
product/list/xxxxx

都轉成
product/enum/xxxxx

這樣一來
所有 url 叫做 product/list 的要求
都會轉到 product/enum

至於 enum 是我自己取的 function name
你可以自己換成你自己想要的 function name

當然比較高級的方法
也可以去改 .htaccess
但是比較複雜
如果不想搞懂 .htaccess 的話
(我一直都不想搞懂啊阿阿阿~~)
用 CI 的 Route 功能是個好方法

如何改寫核心元件 CI_Model – CodeIgniter

(這篇欠超久)
CodeIgniter 寫久了
就會發現其實模式很固定

Controller 跟 Model 裡面的 function 大概就那些
用 Copy 的容易發生錯誤

於是就想把它變成 default 的 function
只要把 code 填進去
或是用參數來決定就好

例如 Model 是控制資料庫資料存取的
基本上一定會有
create/select/update/delete 幾個動作

如果能把這些 function 先寫好
在把欄位的部份抽出來變成設定
那就可以少掉很多功夫
debug 也會更方便

改寫的方法如下
首先 先在 application/core 內建立一個 MY_Model.php 的檔案

檔案裡面的內容如下
註: 底下程式直接執行會有一些變數未定義的錯誤
因為我已經把一些設定值拔掉
目的只是純粹表達概念

<?php  if (!defined('BASEPATH')) exit('No direct script access allowed');
class MY_Model extends CI_Model
{
public function __construct($config=array())
{
parent::__construct();
}
public function get($idx)
{
$this->db->select('*');
$this->db->where('idx', $idx);
$res       = $this->db->get($this->table);
$item       = $res->row_array();
if(empty($item)) return null;
}
public function insert($data)
{
$this->db->insert($this->table, $data);
$idx       = $this->db->insert_id();
$this->Item_order->update_order_idx($this->table, $idx);
if($this->image_upload)
$this->upload_image($idx);
$this->SEO->update_by_form($this->model_name, $idx);
$this->Modify_history->insert($this->model_name, $idx, 'insert');
return $idx;
}
public function update($idx, $data)
{
$this->db->where('idx', $idx);
$this->db->update($this->table, $data);
if($this->image_upload)
$this->upload_image($idx);
$this->SEO->update_by_form($this->model_name, $idx);
$this->Modify_history->insert($this->model_name, $idx, 'update');
return $idx;
}
public function delete($idx)
{
$this->db->where('idx', $idx);
$this->db->delete($this->table);
}
}
/* End of file MY_Model.php */
/* Location: ./application/core/MY_Model.php */

裡面有一些存取 db 的基本 function
對 db 來說, 可能都會類似像 get 這個 function 一樣
傳入一些固定的值
然後從 db 取值, 或是寫值進去

寫入什麼資料欄位 由外部傳入
重複的部份都放進這個 MY_Model 的 class 裡面

像我有些模組可能需要上傳圖片
寫一些 SEO 資訊
跟記錄這筆資料是誰變更的
這些瑣碎但是固定的事情
都可以移到這層來
以後要修改就不用每個 model 都改
充分發揮物件導向的特性

寫好以後
如果有要繼承這個 base class 的 model
可以這樣寫

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Banner extends MY_Model {
public function __construct()
{
parent::__construct($config);
}
public function insert()
{
$data       = array();
$data['title']     = $this->input->post('title');
$data['link']     = $this->input->post('link');
$idx       = parent::insert($data);
return $idx;
}
public function update($idx)
{
$data       = array();
$data['title']     = $this->input->post('title');
$data['link']     = $this->input->post('link');
$idx       = parent::update($idx, $data);
return $idx;
}
}
/* End of file banner.php */
/* Location: ./application/model/customize/banner.php */

注意
繼承的部份已經從 CI_Model 改成 MY_Model 了
其他寫好就都一樣
寫你想寫的步驟跟流程
但是不一樣的是
這層的 code 就更少了

只要把一些要操作的資料準備好
往 MY_Model 丟就好了

甚至像 get 這種拔辣的 function
根本不用寫
直接用 MY_Model 的 function 就好了

以後新增 model 的時候
copy 的 code 變少了
要改的 code 也少很多

這樣 bug 應該可以少很多
製作時間也可以縮短

真是一整個歡樂

結論
其實一個系統好好研究
可以改良的地方真的很多
別小看這些小動作
節省時間 提昇效率 減少錯誤
就可以賺更多錢

[CodeIgniter] RSS Parser

因為工作需要
找了一個專為 CodeIgniter 寫的 RSS Parser

Codeigniter-RSSParser

用法很簡單
把 library 放在 application/libraries/ 中即可

$this->load->library('rssparser');                          // load library
$this->rssparser->set_feed_url('http://example.com/feed');  // get feed
$this->rssparser->set_cache_life(30);                       // Set cache life time in minutes
$rss = $this->rssparser->getFeed(6);                        // Get six items from the feed

回傳的 $rss 是一個 array
裡面有
title, description, author, pubDate, link
就看怎麼自由運用啦

他也支援串接的功能

$this->rssparser->set_feed_url('http://example.com/feed')->set_cache_life(30)->getFeed(6);

但是個人覺得這樣寫只是工程師爽而已
對閱讀性來說很差

其他零碎功能或是 function 的用法可以參考官網~