分类存档: PHP - 第2页

Magento 在首页显示产品

Mangento默认首页并不会显示任何产品,如果需要在首页显示,则需要在cms=>pages=>home添加

{{block type=”catalog/product_list” category_id=”3″ template=”catalog/product/list.phtml”}}

继续阅读 »

Magento模块学习

Magento 模块

模块( module )是 Magento 的核心。站点上的任何一个动作( action ),无论是在前台和还是在后台的每一个操作都是通过模块来实现的。模块是可以视为一个容器,它可包含下面这几项:设置 (settings) ,数据库模式 (database schema) ,呈现对象 (rendering object) ,辅助工具类 (utility helpers) ,数据模型 (data models) 或动作控制器 (action controller) 。一个模块可以包含全部的这六项也可以只包含其中的几项,甚至只有一项。所有的模块可以通过 app/etc/modules/ 目录中 XML 配置系统来进行开关。每个模块也可以在自己模块目录下的 etc 子目录中创建一个 XML 文件来保存自己的配置信息。

由于 Magento 中的一切都是模块而且模块本身又可以有自己的配置文件和数据库设置,这样就允许开发人员对 Magento 进行扩展。

继续阅读 »

Magento 引用include顺序

Magento 1.6.2引用文件(include)顺序先后分别是:

app/code/local
app/code/community
app/code/core
lib
.
/usr/local/lib/php
/usr/local/lib/php/PEAR
/usr/local/lib

也就是因为这个local到community最后才到core的顺序,Magento无法优先加载你的同名类.这点可以在重写Magento核心模块时用到.

继续阅读 »

[原创]Joomla+Ucenter(discuz)整合同步登录的插件

支持Joomla 1.7/2.5,UCenter 1.6.
注:Joomla 2.5.4后,因为对原来核心组件模块锁定了,不能从后台替换核心模块/插件。此问题正在解决中。
解决方法:

使用phpMyAdmin打开表:,然后找到name的值为plg_authentication_joomla的插件,然后修改这条记录。把enabled和protected均设值为0。
实现功能:

1.当从Joomla登录时,如果UCenter用户存在,则使用UCenter上的用户信息校验密码.则否使用Joomla本地信息.同步更新,删除Joomla和UCenter用户.

2.可选只使用UCenter用户信息,而不理会Joomla本地用户信息.

3.可选同步登录,删除,更新用户时,是否先检查用户是否存在重得,如果重得,则不作同步.

4.组件后台提供用户复制功能.按UCenter官方手册建议,使用前最好先将Joomla用户复制到UCenter.并需要处理好用户重名的问题.如果你的Joomla是新的,没有任何用户,可以不复制用户.如果你的系统存在除UCenter和Joomla之外的其它应用,建议纳UC官方的建议.否则可能出现权限提供的问题.

具个例子,某用户A在Joomla中是管理员,而之前并没在UC中.且在您的系统合并后,用户A一直没有登录过,就是说这个用户A一直没有被同步到UC中,而后来用户B却跑到你的第三方应用,如DZ X2注册了与用户A同名用户.那么当这个假的用户A从X2登录后,也能同步登录到Joomla中,原来的用户A,就无法再正常登录了.按UC官方的建议,事先将用户复制到UC的话,就可以很好地解决这个安全问题.

我发现其它同类插件很少提及到这点.

5.安装即用,不修改Joomla原来代码.

继续阅读 »

Discuz! X2源码分析-插件机制

以下是我的阅读笔记.方便日后记忆.

插件事件勾子默认入口:runhooks函数.主要运行插件初始函数和全局方法,如:common(),HookId().

先看源码,
source/function/function_core.php 约1191行开始:

function runhooks() {
if(!defined(‘HOOKTYPE’)) {
define(‘HOOKTYPE’, !defined(‘IN_MOBILE’) ? ‘hookscript’ : ‘hookscriptmobile’);
}
if(defined(‘CURMODULE’)) {
global $_G;
if($_G[‘setting’][‘plugins’][HOOKTYPE.’_common’]) {
hookscript(‘common’, ‘global’, ‘funcs’, array(), ‘common’);
}
hookscript(CURMODULE, $_G[‘basescript’]);
}
}

其中,HOOKTYPE当电脑浏览时是指hookscript,手机浏览时hookscriptmobile.

CURMODULE其实就是url中的$mod=XXX,其实就是常见的$action,也不是动作.以下代码是插件中的commom()方法.

if($_G[‘setting’][‘plugins’][HOOKTYPE.’_common’]) {
hookscript(‘common’, ‘global’, ‘funcs’, array(), ‘common’);
}

接着,$_G[‘basescript’]是当然的主程序名称,比如,forum.php?mod=XXX&do=XX,那么$_G[‘basescript’]就是forum.

hookscript运行在当前主程序下注册的相关函数.

接着是hookscript函数,这个是插件机制的重心.内容很多,我就直接在里面写注释好了.

/**
* @param String $script 事件勾子名称
* @param String $hscript 事件勾子所在的区域,常的有global,forum,home,member等,就是某个大块
* @param String $type 事件类型,一般都是函数形式,funcs
* @param Array $param 给给被调用的函数的参数.这是一个特殊的数组, 一般地,也会传递调用hookscript函数的函数的所有参数,读起来有点别扭:)有时候还会添加一些特殊的内容,如step等.
* @param Array $func 被调用的函数.虽然使用了=”的方式正义,但看过代码后,我觉得还是使用Array来正义它的类型会好些.
*/
function hookscript($script, $hscript, $type = ‘funcs’, $param = array(), $func = ”) {
global $_G;
static $pluginclasses;

#对家园这类勾子做特别处理.
if($hscript == ‘home’) {
if($script != ‘spacecp’) {
$script = ‘space_’.(!empty($_G[‘gp_do’]) ? $_G[‘gp_do’] : (!empty($_GET[‘do’]) ? $_GET[‘do’] : ”));
} else {
$script .= !empty($_G[‘gp_ac’]) ? ‘_’.$_G[‘gp_ac’] : (!empty($_GET[‘ac’]) ? ‘_’.$_GET[‘ac’] : ”);
}
}
#没有注册勾子,直接返回.
if(!isset($_G[‘setting’][HOOKTYPE][$hscript][$script][$type])) {
return;
}
#加载插件缓存
if(!isset($_G[‘cache’][‘plugin’])) {
loadcache(‘plugin’);
}

#引用插件主类所在文件
foreach((array)$_G[‘setting’][HOOKTYPE][$hscript][$script][‘module’] as $identifier => $include) {
$hooksadminid[$identifier] = !$_G[‘setting’][HOOKTYPE][$hscript][$script][‘adminid’][$identifier] || ($_G[‘setting’][HOOKTYPE][$hscript][$script][‘adminid’][$identifier] && $_G[‘adminid’] > 0 && $_G[‘setting’][‘hookscript’][$hscript][$script][‘adminid’][$identifier] >= $_G[‘adminid’]);
if($hooksadminid[$identifier]) {
@include_once DISCUZ_ROOT.’./source/plugin/’.$include.’.class.php’;
}
}
if(@is_array($_G[‘setting’][HOOKTYPE][$hscript][$script][$type])) {
$_G[‘inhookscript’] = true;
/**
* 自动校正第五个参数,以取得正确的调用函数.
* OK,$_G[‘setting’][HOOKTYPE][$hscript][$script][$type] = $_G[‘setting’][‘hookscript’][‘forum’][‘viewthread’][‘funcs’]
* print_r($_G[‘setting’][HOOKTYPE][$hscript][$script][$type]);
* 得到类似下面的结果:
* Array
* (
* [viewthread_posttop] => Array
* (
* [0] => Array
* (
* [0] => tbackup
* [1] => viewthread_posttop
* )
*
* )
* )
*/
$funcs = !$func ? $_G[‘setting’][HOOKTYPE][$hscript][$script][$type] : array($func => $_G[‘setting’][HOOKTYPE][$hscript][$script][$type][$func]);

#展开$funcs数组第一层:[viewthread_posttop] => Array
foreach($funcs as $hookkey => $hookfuncs) {
#再展开viewthread_posttop数组下的每个项:0~N
foreach($hookfuncs as $hookfunc) {
#$hookfunc[0]是插件类的identifier(例中的是:tbackup),而$hookfunc[1]则是类下面注册的一个方法(例中的是:viewthread_posttop)
if($hooksadminid[$hookfunc[0]]) {
$classkey = (HOOKTYPE != ‘hookscriptmobile’ ? ” : ‘mobile’).’plugin_’.($hookfunc[0].($hscript != ‘global’ ? ‘_’.$hscript : ”));
#无此类,跳过.
if(!class_exists($classkey)) {
continue;
}
#此类未在插件中注册,也跳过
if(!isset($pluginclasses[$classkey])) {
$pluginclasses[$classkey] = new $classkey;
}
#此类中无此方法,例中的是:viewthread_posttop,也跳过.
if(!method_exists($pluginclasses[$classkey], $hookfunc[1])) {
continue;
}
#执行类中的方法,例中的是:$pluginclasses[‘tbackup’]->viewthread_posttop($param)
$return = $pluginclasses[$classkey]->$hookfunc[1]($param);
#print_r($return);
#Array ( [0] => HI )
#如果返回的是数组,那么将$retgurn的$key和$value插入到$_G[‘setting’][‘pluginhooks’][$hookkey]中,在例中是$_G[‘setting’][‘pluginhooks’][‘tbackup’]
if(is_array($return)) {
if(!isset($_G[‘setting’][‘pluginhooks’][$hookkey]) || is_array($_G[‘setting’][‘pluginhooks’][$hookkey])) {
foreach($return as $k => $v) {
$_G[‘setting’][‘pluginhooks’][$hookkey][$k] .= $v;
}
}
} else {
/**
* $return非数组的情况下,
* 如果$_G[‘setting’][‘pluginhooks’][$hookkey]本身不是数组(一般说,它就是要求字符串的),那么直接把返回值$return追加到$_G[‘setting’][‘pluginhooks’][$hookkey]后在面
* */
if(!is_array($_G[‘setting’][‘pluginhooks’][$hookkey])) {
$_G[‘setting’][‘pluginhooks’][$hookkey] .= $return;
} else {
/**
* 如果$_G[‘setting’][‘pluginhooks’][$hookkey]本身就是数组(一般说,它就是要求返回数组的),那么把$return的每个KEY追加到
* $_G[‘setting’][‘pluginhooks’][$hookkey]对应的KEY后面.从而达到当$return为数组的情况一样的效果.
* */
foreach($_G[‘setting’][‘pluginhooks’][$hookkey] as $k => $v) {
$_G[‘setting’][‘pluginhooks’][$hookkey][$k] .= $return;
}
}
}
}
}
}
}
#更新标记,说明我已经跳出插件勾子啦!
$_G[‘inhookscript’] = false;
}

举个例子,实现在查看主题页面的下面添加”HI”.

class plugin_tbackup_forum extends plugin_tbackup {

function viewthread_bottom() {
return array(“HI”);
}
}

但是,有时候DZ定义的勾子不够多也不够细化,那么就只能请求全局勾子来帮下忙了.
全局勾子是hookscriptoutput,它本义是用于输出调试信息的.

/**
* hookscript的一个特例,当在某个模板准备输出时调用.
* @param String $tplfile 模板名,如viewthread
*
* */
function hookscriptoutput($tplfile) {
global $_G;
if(!empty($_G[‘hookscriptoutput’])) {
return;
}

/**
* 这块是手机的
* */
if(!empty($_G[‘gp_mobiledata’])) {
require_once libfile(‘class/mobiledata’);
$mobiledata = new mobiledata();
if($mobiledata->validator()) {
$mobiledata->outputvariables();
}
}
hookscript(‘global’, ‘global’);
if(defined(‘CURMODULE’)) {
$param = array(‘template’ => $tplfile, ‘message’ => $_G[‘hookscriptmessage’], ‘values’ => $_G[‘hookscriptvalues’]);
hookscript(CURMODULE, $_G[‘basescript’], ‘outputfuncs’, $param);
}
$_G[‘hookscriptoutput’] = true;
}

hookscriptoutput应该是用来DEBUG的,本身可以做的事不多,但是,如果你对DZ代码很了解的话,你可以修改任何GLOBAL中的内容,下面来个例子,用于修改每个帖子中的签名(DZ本身没有修改签名的勾子).

class plugin_tbackup_forum extends plugin_tbackup {

function viewthread_output($param) {
global $postlist;
foreach ((array) $postlist as $k=>$post) {
$postlist[$k][‘signature’] = “HI,Tim”;
}

}
}

例中,通过global $postlist;来引入全局程序中的$postlist也就是帖子列表.然后一个foreaech把$post里的signature修改掉.有心的朋友可以扩展下,$postlist[$k][‘signature’] = “HI,Tim”;可以改成一个过滤函数,那么不就可以过滤掉一些你不喜欢的签名了吗?

继续阅读 »

DX分布式部署值得期待

看了DZ官方WIKI发出的DX分布式部署图,觉得DZ X2.5应该值得期待。按上面的介绍,X2.5将可以将不同的表分布到不同的服务器中。例中具出了分29个服务器的示例。
其实这个功能已经在X2.0中显示出了一个雏形,那就是数据库主从数据库分离,特别是可以指定哪些表不进行分离。
官方原图:

不过X2.5与X2.0的改动会很大,不再支持PHP 4.X了。看来又有很多朋友要重新熟悉它了。

继续阅读 »

Linux+Nginx+PHP+MySQL+MemCached+eaccelerator安装优化记录

近日,某论坛因发展需要,增加了一台服务器,他们装好系统,叫我帮安装服务器环境,数据同步处理并希望做到负载均衡等。以下为过程记录。中间可能会有些过程被跳过,本来想写成教程的,但是年关已近,实在是太多事情需要处理。现只能先把记录发上来,以后看有没有时间重新整理成教程。

需要安装的软件:

Web服务器软件:Nginx 1.0.11
FCGI:PHP 5.2.17
数据库:MySQL 5.1.x(服务器A),MySQL 5.5(服务器B)
服务器优化:MemCached,eaccelerator,google-perftools
实时同步软件:rsync,inotify-tools

以下是两服务器可以相同的操作记录:

继续阅读 »

可以自动备份被删除的帖子的DZ X2 插件 tbackup

由于特殊的需求,一个discuz x2.0的论坛,为防止有删除帖子权限的后台用户密码被泄露而导致大量精华帖子被删除,所以我花一天的时候开发了这个插件。

插件有这样的功能:不管是任何人(哪怕是创始人),不管是在前后或者后台删除了某个帖子,此插件都能在DZ物理删除这个帖子之前做一个备份,备份到另一个表中,日后可以通过后台还原这个帖子。

此插件有区别于DZ X2自带的回收站。当帖子前入回收站时,此插件不做任何动作,但是如果你从回收站彻底删除或者清空回收站时,此插件发挥作用。如果你的论坛已经有日常备份了,此插件也还是能帮上你不少忙的,你只要在后台点几下,就可以还原了,不用把很多不心要的东西都还原。

如果你的论坛内容很重要,且由很多拥有删除帖子权限的版主或者管理员来进行日常维护的话,这个插件很有用。另外,X2好像有个BUG,不管你有没有选中自动登录,你如果不点注销,下次你还一定是自动登录,如果你的一个版主在公共场所登录了,那么,可想那是多么可怕的事。

继续阅读 »

使用php取得android APK文件信息和图标

虽然PHP不能直接获取android APK软件包的信息,但是可以通过调用google发行的android-apktool来取得文件信息的,需要exec支持。

首先需要安装android-apktool:

继续阅读 »

PHP安装XSLT模块支持

首选安装libgpg-error-devel 和libgcrypt-devel

yum install libgpg-error-devel libgcrypt-devel

然后转到PHP源码目录:

./configure –enable-fastcgi –enable-fpm –with-mysql –with-mysqli –with-gd –with-config-file-path=/etc –with-config-file-scan-dir=/etc/php.d –with-curl –enable-calendar –with-openssl –with-zlib –without-sqlite –disable-pdo –enable-mbstring –with-freetype-dir=/usr –enable-sockets –enable-zip –with-mcrypt –with-mhash –with-jpeg-dir=/usr –enable-ftp –with-xsl

继续阅读 »

第 2 页,共 3 页123