forecho 的独立博客

把生命浪费在美好的事物上

yii隐藏index.php而不隐藏admin.php的方法

2012年11月06日

之前我介绍过yii模块的使用,使用模块的方法可以帮我们实现前后台分离的工作,但是本人不是很喜欢这个方法,个人认为模块是用来扩展的。 于是我又使用单独的入口文件,具体可以参考这篇文章。 这个时候我又想隐藏掉前台URL中的index.php,于是在网上找了一些资料,整合了这篇文章。 但是现在问题出现了,安装那个办法确实把前台中的index.php隐藏掉了,但同时也隐藏掉了admin.php,于是进入后台的时候URL就乱套了。路径都有问题。 解决办法就是: 在protected/admin/config/main.php文件中加入下面一行代码:

$frontendArray=require($frontend.'/config/main.php');
unset($frontendArray['components']['urlManager']);//不隐藏后台URL中的admin.php

yii自定义URL

2012年11月05日

1、首先找到 protected/config/main.php配置文件。找到如下图代码块: 把urlManager整个的注释都取消掉。 2、添加两行代码,示例如下:

'urlManager'=>array(
            'urlFormat'=>'path',
            'showScriptName' => false,// 使用URL重写,去掉index.php 
            'urlSuffix' => '.html',//开启伪静态
            'rules'=>array(
                '<controller:\w+>/<id:\d+>'=>'<controller>/view',
                '<controller:\w+>/<action:\w+>/<id:\d+>'=>'<controller>/<action>',
                '<controller:\w+>/<action:\w+>'=>'<controller>/<action>',
            ),
        ),

3、需要在项目的更目录下创建.htaccess内容如下:

Options +FollowSymLinks
IndexIgnore */*
RewriteEngine on

# if a directory or a file exists, use it directly
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d

# otherwise forward it to index.php
RewriteRule . index.php

OK,这时候基本的需求已经满足了,下面我们要扩展一下 urlManager 有时候会根据项目的需求需要扩展url,那么这个时候我们只需要简单的在urlManager的rules里面扩展就OK了。示例代码如下:

array(
    'posts'=>'post/list',
    'post/<id:\d+>'=>'post/read',
    'post/<year:\d{4}>/<title>'=>'post/read',
)
  • 调用$this->createUrl(‘post/list’)生成/index.php/posts。第一个规则适用。
  • 调用$this->createUrl(‘post/read’,array(‘id’=>100))生成/index.php/post/100。第二个规则适用。
  • 调用$this->createUrl(‘post/read’,array(‘year’=>2008,’title’=>’a sample post’))生成/index.php/post/2008/a%20sample%20post。第三个规则适用。
  • 调用$this->createUrl(‘post/read’)产生/index.php/post/read。请注意,没有规则适用。

只要你愿意,任何时候都不算晚

2012年11月05日

琢磨着趁现在年轻多学点东西,想让自己变得果断一点,于是乎在8月26日以迅雷不及掩耳之势买下了一台Macbook Pro。

然后最近自己又买了本《iOS5基础教程》,看了一些,想从事iOS

开发之路。

在公司还是继续讲究YII框架,琢磨着今年年底之前能使用YII框架写出个完整的网站出来。

前一段时间看了一篇文章《同时学习多种编程语言其实很容易》,其实讲的还算是有道理。各种语言其实学到最后大多都差不多了,你更多要学的其实是怎么优化,怎么去设计数据库,怎么去处理并发,内存管理,缓存管理等等。

前一段时间把《送你一颗子弹》看完了,然后发现其实看书还是蛮有意思的,所以打算多看一些书,少刷微博,少刷空间,没劲。

最近疯狂的在找一些科幻的美剧看,比如说找到了《Touch》(触摸未来)、《Fringe》(迷离档案,其实我更喜欢叫它危机边缘),感觉着两部还不错,他们思维比中国的电视剧要开阔要多的多,我本身也是比较喜欢看科幻片的。

突然发现英语的阅读水平对于程序员来说非常重要,所以我有必要重视一下我的英语。

以上差不多就是我为明年去上海(或者北京)做准备了。其实学习这事任何时候都不算晚,只要你来了兴趣。

鉴于每个星期如果坚持写博客的话,只要坚持下来,1年以后你会发现写博客水平会有所提升,几年下来就会有质的提升,于是我就当真了,我信了。

Substr(),mb_substr()及mb_strcut的区别和用法

2012年11月01日

substr()函数可以分割文字,但要分割的文字如果包括中文字符往往会遇到问题,这时可以用mb_substr()/mb_strcut这个函数,mb_substr()/mb_strcut的用法与substr()相似,只是在mb_substr()/mb_strcut最后要加入多一个参数,以设定字符串的编码,但是一般的服务器都没打开php_mbstring.dll,需要在php.ini在把php_mbstring.dll打开。 举个例子:

1
2
3
<?php
    echo mb_substr('这样一来我的字符串就不会有乱码^_^', 0, 7, 'utf-8');
?>

输出:这样一来我的字

1
2
3
<?php
    echo mb_strcut('这样一来我的字符串就不会有乱码^_^', 0, 7, 'utf-8');
?>

输出:这样一

从上面的例子可以看出,mb_substr

是按字来切分字符,而mb_strcut是按字节来切分字符,但是都不会产生半个字符的现象……mbstring

函数的说明:

php的mbstring扩展模块提供了多字节字符的处理能力,平常最常用的就是用mbstring来切分多字节的中文字符,这样可以避免出现半个字符的情况,由于是php的扩展,它的性能也要比一些自定义的多字节切分函数要好上一些。

mbstring extension提供了几个功能类似的函数,mb_substr和mb_strcut,看看手册上对它们的解释。 mb_substr mb_substr() returns the portion of str specified by the start and length parameters. mb_substr() performs multi-byte safe substr() operation based on number of characters. Position is counted from the beginning of str. First character’s position is 0. Second character position is 1, and so on. mb_strcut mb_strcut() returns the portion of str specified by the start and length parameters. mb_strcut() performs equivalent operation as mb_substr() with different method. If start position is multi-byte character’s second byte or larger, it starts from first byte of multi-byte character. It subtracts string from str that is shorter than length AND character that is not part of multi-byte string or not being middle of shift sequence.

再举个例子,有一段文字, 分别用mb_substr和mb_strcut来做切分:

1
2
3
4
5
6
<?php
    $str = '我是一串比较长的中文-www.webjx.com';
    echo "mb_substr:" . mb_substr($str, 0, 6, 'utf-8');
    echo "<br>";
    echo "mb_strcut:" . mb_strcut($str, 0, 6, 'utf-8');
?>

输出结果如下:

1
2
mb_substr:我是一串比较
mb_strcut:我是

CI自定义分页类

2012年10月29日

之前我写过一篇文章,介绍了CI如何分页,请猛击~ 那么考虑到一个项目要分页的地方比较多,所以后来我们写了一个单独的分页类,这样一个项目的效率会大大提升。 1、首先,我们在  application / libraries /下面创建page.php(扩展分页类)文件,代码如下:

<?php

class Page
{ 
	protected $url;
	protected $total;
	protected $size;
	protected $segment;
	protected $CI;

	function __construct($value){

		$this->url=$value['url'];
		$this->size=$value['size'];
		$this->total=$value['total'];
		//$this->segment=$value['uri'];

		$this->CI=& get_instance();

		$this->CI->load->library('pagination');

	}

	function fy(){

		return $this->page();

	}

	protected function page(){

		$config['base_url']=base_url($this->url);
		$config['total_rows']=$this->total;
		$config['per_page']=$this->size;
		//$config['uri_segment']=$this->segment;
		//GET分页 传参
		$config['page_query_string'] = TRUE;

		$config['num_links']=3;
		$config['first_link']='首页';
		$config['last_link']='末页';
		$config['prev_link']='上一页';
		$config['next_link']='下一页';
		$config['cur_tag_open'] = ' <a class="current">'; // 当前页开始样式  
		$config['cur_tag_close'] = '</a>'; // 当前页结束样式  

//      $this->CI->load->library('pagination', $config);

		$this->CI->pagination->initialize($config);

		return $this->CI->pagination->create_links();

	}

}

?>

2、那分页类写好了,如何使用呢?在控制器里面 controllers / feadmin.php文件(此处要结合你自己的项目,feadmin.php是我的控制器文件名)。下面是我们文章列表的示例代码:

function postsList() {
		$data['posts'] = $this->fe_model->page('posts', 'feadmin/postsList?',  @$_GET['per_page'], 2, 'id desc','category','posts.category = category.cid ');
		//print_r($data['posts']);
		$data['category'] = $this->fe_model->selectCate();
		//$data['category1'] = $this->fe_model->selectFormWhere('category',);
		//print_r($data['category1']);
        $data['title_for_layout'] = '文章列表';

        $this->load->view('admin/postsView', $data);
    }

此处我使用的是CI** GET分页**方法,具体需要看你的项目是否需要,此处可参考手册开启GET翻页功能。 fe_model是我项目的模型文件,那么要实现翻页,还需要在模型中写下面的方法:

//分页
	function page($form, $url, $offset, $size, $order, $join, $joinArray){

		$fy['url'] = $url;
		$fy['total'] = $data['total'] = $this->fy_n($form);
		$fy['size'] = $data['size'] = $info['size'] = $size;
		//$fy['uri'] = $offset;
		$this->load->library('page', $fy);
		$data['fy'] = $this->page->fy();
		//print_r($data['fy']);
		//$info['start'] = $data['start'] = $this->uri->segment($offset, 0);
		$info['start'] = $data['start'] = $offset;
		$info['order'] = $order;
		$data['admin'] = $this->fy_info($form, $info, $join, $joinArray);

		return $data;

	}

	function fy_n($form){

		return $this->db->get($form)->num_rows();

	}

	function fy_info($form,$value,$join,$joinArray){

		$this->db->order_by($value['order']);
		$this->db->limit($value['size'],$value['start']);
		if($join != ""){
			$this->db->join($join,$joinArray);
		}
		return $this->db->get($form)->result();

	}

	function pageWhere($form, $url, $offset, $size, $where, $order, $join, $joinArray){

			$fy['url'] = $url;
			$fy['total'] = $data['total'] = $this->p_numWhere($form, $where);
			$fy['size'] = $data['size'] =$info['size'] = $size;
			//$fy['uri'] = $offset;
			$this->load->library('page', $fy);
			$data['fy'] = $this->page->fy();
			//print_r($data['fy']);
			//$info['start'] = $data['start'] = $this->uri->segment(offset, 0);
			$info['start'] = $data['start'] = $data['start'] = $offset;
			$info['order'] = $order;
			$data['admin'] = $this->fy_infoWhere($form, $where, $info, $join, $joinArray);

			return $data;

	}
	function p_numWhere($form, $where){

		if(isset($where['where'])){
			$this->db->where($where['where']);
		}
		if(isset($where['like'])){
			$this->db->like($where['like'])	;
		}

		return $this->db->get($form)->num_rows();

	}

	function fy_infoWhere($form, $where, $value, $join, $joinArray){

		if(isset($where['where'])){
			$this->db->where($where['where']);
		}
		if(isset($where['like'])){
			$this->db->like($where['like']);
		}

		$this->db->order_by($value['order']);
		$this->db->limit($value['size'],$value['start']);
		if($join != ""){
			$this->db->join($join,$joinArray);
		}

		return $this->db->get($form)->result();

	}

3、下面的视图文件的代码:

<tbody>
	<?php foreach ($posts['admin'] as $post):
		?>
	<tr>
		<td>
		  <input type="checkbox" name="checkbox[]" value="<?php echo $post->id; ?>" />
		</td>
		<td><a href="feadmin/posts/<?php echo $post->id;?>" title="修改文章"><?php echo $post->title;?></a></td>
		<td><a href="feadmin/postsSearch/?category=<?php echo $post->category;?>" title="查询“<?php echo $post->name;?>”分类"><?php echo $post->name;?></a></td>
		<!-- <td><?php //echo date('Y-m-d', strtotime($post->addtime));?></td> -->
		<td><?php echo $post->addtime;?></td>
		<td>
			<a href="feadmin/posts/<?php echo $post->id;?>" title="修改"><img src="resources/images/icons/pencil.png" alt="修改" /></a> 
			<?php if($post->type != 1){?>
				<a href="feadmin/postsDelete/<?php echo $post->id;?>" title="删除" onclick="return(confirm('确定删除?'))"><img src="resources/images/icons/cross.png" alt="删除" /></a> 
				<!-- <a href="#" title="Edit Meta"><img src="resources/images/icons/hammer_screwdriver.png" alt="Edit Meta" /></a> -->
			<?php }?>
		</td>
	</tr>
  <?php 
  endforeach;?>
</tbody>

翻页的按钮代码如下:

<div class="pagination">
	<?php echo $this->pagination->create_links(); ?>
</div>

此处值得注意的是   完整项目代码请参考这里~

iOS开发实例(三)-“按钮”

2012年10月23日

如果第4步不能直接关联了,因为是个 UIview,没有动作,那么你需要在按钮上右键,然后点住Touch Up Inside再拖到辅助编辑器中间位置。 ================以上为Update 2013年11月23日================== 与用户交互是应用程序的一种重要功能。 我们首先按照实例一的步骤创建一个新的项目—–》Button Fun。 项目创建好之后的文件除了项目名不同,其他的应该和实例一的截图一样。   1、首先我们需要清理一下试图控制器(简化代码,删除没必要的代码)。找到BIDViewController.m文件,源代码如下图: 删减之后的代码如下:

#import "BIDViewController.h"
@implementation BIDViewController

- (void)viewDidUnload
{
    [super viewDidUnload];
    // Release any retained subviews of the main view.
    //e.g.self.myOutlet = nil;
}

@end

2、设计用户界面:点击BIDViewController.xib文件。可以根据之前的实例一来操作,我们找到Round Rect Button,然后直接按住鼠标左键拖到界面,放到适合的位置,然后命名为”Left“,如下图操作: 3、开启辅助编辑器。找到编辑器右上角的Editor,点击一下中间的图标即为开启辅助编辑模式。 4、然后我们按住键盘的control键同时按住鼠标左键把按钮拖到辅助编辑器中间位置,如下图所示: 然后会出现一个弹出框,我们把第一项改为“Action”(Action为操作方法,默认的Outlet为输出口),其他的可以按照下图去修改: 然后确定,Xcode会自动生成一行如下代码:

- (IBAction)buttonPressed:(UIButton *)sender;

5、然后我们再去添加另外一个按钮,把这个按钮命名为“Right”,拖到相应的位置;然后按住control键和鼠标左键,把Right按钮拖到之前的代码上面,如下图: 这样操作Xcode会自动关联该按钮和已存在的操作。 6、添加一个标签和输出口。添加一个Label到按钮上方,并且去掉其中的字,拉长与两边按钮对其,在如下图位置设置文字居中: 然后也是按住control键和鼠标左键拖到Label到BIDViewController.h文件中间,并且修改弹出框,如下图操作: 然后确定,Xcode会自动生产一行代码:

@property (strong, nonatomic) IBOutlet UILabel *statusText;

6、这个时候我们的BIDViewController.m文件会多了两行代码,变成如下所示: 然后创建buttonPressed方法,相应的代码添加之后为:

- (IBAction)buttonPressed:(UIButton *)sender {
    NSString *title = [sender titleForState:UIControlStateNormal];
    statusText.text = [NSString stringWithFormat:@"%@ button pressed.",title];
}
@end

    OK,程序基本上算是完成了,这个时候你可以Run一下,然后默认情况下是两个按钮,然后你点击按钮会出现相应的文字提示。如果你看到下图,那么代表你成功了。 -—本节完—-

CodeIgniter备份功能

2012年10月23日

首先我犯了一个错误,就是表命名的时候使用了,特殊的数据字符,所以以后的项目请使用表前缀,可以尽量避免犯没必要而且很蛋疼的错误。 CI的database.php中的 $db[‘default’][‘dbprefix’] = ‘ ‘; 可以设置表前缀。 但是要注意一点:此功能只支持CI自带的Active Record 类,也就是说自己的写的sql语句是不支持的。   下面是根据手册写出的备份方法:

// 备份
function backup(){

	$this->load->dbutil();

	$this->load->helper('file');

	$prefs = array(
			'tables'      => array(),  // 包含了需备份的表名的数组.如果留空将备份所有数据表
			'ignore'      => array(),           // 备份时需要被忽略的表
			'format'      => 'zip',             // gzip, zip, txt
			'filename'    => 'mybackup'.date('Ymd').'.sql',    // 文件名 - 如果选择了ZIP压缩,此项就是必需的
			'add_drop'    => TRUE,              // 是否要在备份文件中添加 DROP TABLE 语句
			'add_insert'  => TRUE,              // 是否要在备份文件中添加 INSERT 语句
			'newline'     => "\n"               // 备份文件中的换行符
				  );

	$backup = $this->dbutil->backup($prefs);

	write_file('./mybackup'.date('Ymd').'.sql', $backup); 

}

为了让程序自动执行,每天备份一次,我在后台控制器的index方法中写了下面的代码:

//检查是否存在文件,即是否备份,如果文件不存在则执行备份			
$filename = './mybackup'.date('Ymd').'.sql';
if (!file_exists($filename)){
	$this->backup();
}
//删除一个星期之前的备份文件
$oldfilename = './mybackup'.date('Ymd',(time()-3600*24*7)).'.sql';
if (file_exists($oldfilename)){
	@unlink($oldfilename);
}

备份完成。至于还原数据库,未完待续————

iOS开发实例(二)-“美化iPhone图标”

2012年10月22日

1、iPhone图标一般都是.png格式文件。 2、一般都是57px57px,一般命名为icon.png;114px114px为Retina屏专用的,一般命名为icon@2x.png。 3、创建图标的时候为一般正方形图片即可,iPhone将自动为图标调整圆角边缘,并且自动加上玻璃质感的效果。   图标制作好之后,按照下面1-》2->3找到相应的位置: 把之前制作的.png文件拖到相应的位置即可(114px的文件放在右边窗口)。 然后两个图标文件会自动载入,为了方便起见我们可以把这两个文件拖到Supporting Files文件夹里。 我们可以在Hello_World_Info.plist能找到相应的配置,如下图:   PS:Bundle identifier(束标示符)标准命名规则是:顶级Internet域名,之后是点号,之后是公司名或者是组织名,再点号,最后是应用名。如果要改束标示符的话就在这里改。 未完待续————

iOS开发实例(一)-“Hello World”

2012年10月21日

本教程是根据《iOS基础教程》一书总结而来。 1、首先打开Xcode,然后创建一个项目,选择iOS-》Application-》Single View Application(一个最简单的模板) 点击Next,如下图所示: 2、然后会出现下图所示内容,你可以安装下图填好相应的资料。 简单的解释一下: 第一项:项目名。 第二项:组织名称。 第三项:公司标识。 Class Prefix:创建所有类的前缀。 Devices:指所适用的设备。 说下最后三个复选框。 第一个就是我们说的新特性之一,用storyboards管理布局文件。 第二个ARC(自动引用计数)机制。 第三个自动生成一个测试用例。 然后点Next。   3、然后我们得到如下结构的文件: 简单的说一下上图文件夹: Hello World:以项目名命名的文件夹,包含了大部分代码以及组成应用程序用户界面的文件 其中BIDViewController.xib:该文件包含特定于项目主试图控制器的用户界面元素。 Supporting Files:包含项目中所需的非Objective-C类的源代码文件和资源文件。(适用这个文件夹次数比较少?)。 Frameworks:一种特殊的类库。包含代码、图像、声音文件等资源。   4、点击BIDViewController.xib文件,然后出现的就是Interface Builder(整合到Xcode里面的界面设计工具),如下图:   5、然后你就可以在右下角的类库里面直接拖过来使用。找到Label,直接拖到用户界面任意位置,然后该文字为“Hello World”,OK,这时候基本上算是完成了,点击一下Xcode左上角的Run,然后自动会调用模拟器,然后界面会出现如下所示界面,代表你成功了。   6、回过头来,我们还可以在标签属性里面直接更改资料,然后保存,然后Run。   第一节完毕,整个过程我们还没有动过一个代码。(注意,网上有说对于新手来说最好不要用ARC来自动管理内存,因为到后面你会有很大的麻烦。但是本教程是根据《iOS基础教程》总结的,书上是这么使用的,对于新手来说的话,只能先这样了。)

PHP之无限极分类

2012年10月16日

用到今天发现一个严重的错误,在id超过两位数的时候,排序是有问题的。如下图错误的排序: 你会发现如果按照as出来的bpath排序的话,cid为55的排序错误,正确的情况是cid为55的应该在101前面,出错的原因是bpath是一个字符串,它会安装字符串来排序,以 “-”  为分节符第一位是0一位数,55的第二位为55两位数,101的第三位数为101三位数。位数不同导致排序不正确的BUG,解决办法就是让cid的位数固定下来,不够的前面填充0,这里我们就用到了MySQL的ZEROFILL

Zerofill

用于数字类型的定长显示是最适合不过了, 长度不够时,用0填充。

那么我们在MySQL里面执行下面的命令,改变表结构:

ALTER TABLE `category` CHANGE COLUMN `id` `id` INT(9) UNSIGNED ZEROFILL NOT NULL AUTO_INCREMENT

现在你再执行查询,结果如下: 现在的补救方法要么就是把子类删除掉,要么就是手动添加path的0保证位数相同。(不要太在意上图的cid,其实就是等同于本文的id。只是换了个名字而已。) ============以上信息update 于2014年1月10日============ 目前写无限极分类的大致分为三种情况:

  1. 递归(效率太慢)
  2. ajax(不会的话,就写不出来)
  3. 继承关系(方法简单,实用) 数据库结构如下图:   主要思想是通过path这个字段通过MySQL 的concat 函数查询实现。示例代码如下:
SELECT id, path, name, CONCAT( path,  '-', id ) AS bpath FROM  `category` ORDER BY bpath

bpath:虚拟字段 内容字段如下:   视图主要代码如下:

<select name="id" class="small-input">
    <option value="0">根目录</option>
    <?php foreach($category as $row):?>
    <option value="<?php echo $row->id;?>">
        <?php
          $count = count(explode('-',$row->bpath));
          echo '|';
          for($i=1;$i<$count;$i++){
               echo '—';
           }   
          echo $row->name;?>
     </option>
    <?php endforeach;?>
</select>

  添加新栏目的话,主要思想是的把父级的path 和pid链接起来,组成新的path。 详细代码请参考我的gitbub 的Fecms项目,敬请期待。