workerman+yii实现快速开发交互

示例:

http://24.igd.cc/workerman/page?caihaibin=ok

外部使用demo

http://24.igd.cc/workerman_remote/page?caihaibin=ok

http://gxu.igd.cn/workerman_remote/page?caihaibin=ok

(端口只有一个, 多个项目使用同一个workerman,通过特殊机制,实现将workerman请求转发到yii,并共享两边的sessiono数据,支持wss)

需要明确一个关键点,workerman本身是一个独立的运行容器,类似 apache+php的概念,独立运行.

http://24.igd.cc/workerman_remote/page?caihaibin=ok

因为 workerman 是一个独立的脚本容器,所以这类代码

lib ( ‘workerman/Gateway.php’ );
\GatewayClient\Gateway::joinGroup ( State ( ‘client_id’ ), WebSocketTools::KEY_PRE . ‘test’ );

其实比较像调用workerman的接口,实现相关功能.需要理解这块,所以两者有一定的时间差,这块初试化时,必须认login推送返回的消息为准,做为完全建立两者通讯的标志.如果没有,页面应当进行刷新,再次进行连接.有时websocket open是成功的,但是login消息也会没有推送回来,表示之前的网络通讯出了问题.当做不成功.

 

workerman 游戏的两种模式

第一种:

一种频率不高的,几秒甚至十几秒点一次的,如猜拳,24点小游戏.直接使用post调用yii动作实现游戏逻辑.

第二种:

频率非常高的,类似数钱,一秒会有数次请求的,全部走workerman session,不经过yii session 和数据库. 前台屏幕数据显示,可通过gatewayclient获取workerman所有的会话数据,再根据数据进行排名显示. 当比赛结束时,再将数据插入数据库.

//===============发送workerman 内部参数,用于直接调用workerman动作===============
// 自定义一个key 和 value ,一秒内多次推送也不影响性能
ws.send(JSON.stringify({model:’__workerman’,action:’set_value’,value_key:’score’,value_value:Math.random(0)}));
//===============发送workerman 内部参数,用于直接调用workerman动作

//gateway 获取session数据,不同项目,分组前缀必须不同,防止冲突

Gateway::getAllClientSessions ( WebSocketTools::KEY_PRE . ‘test’ )

广度workerman时序图

 

写给公司的yii1到yii2的转化

只针对模块形式代码进行yii1到yii2的转化,config中需要手动进行补充配置.
<?PHP
header ( 'Content-Type: text/html; charset=utf-8' );
include 'FileTools.php';
include 'lib.php';
// 需要转换的模块
$path = 'D:/PHPnow-1.5.6/htdocs/igddata/yii2sys/app/modules/member/';
// $path = 'D:/PHPnow-1.5.6/htdocs/igddata/yii2sys/app/';
// 根路径,用于识别命名空间
$root_path = 'D:/PHPnow-1.5.6/htdocs/igddata/yii2sys/';
$root_path = preg_replace ( '/\//', '\\', $root_path );
$preg_file = array ();
// Yii::$app->user->setState('_id',$identity->_id); 修改 成 Yii::$app->session->set ( '_id', $identity->getId () );
// ar getList findAll 需要针对性处理.
// CHTML
// <?
$preg_contents = array (
		'/Yii\:\:app\s*?\(\)/' => 'Yii::$app',
		// $app->params->membermodules => 变成数组 ['membermodules']
		'/Yii\:\:\$app\-\>params\-\>(\w+)/' => 'Yii::$app->params[\'\\1\']',
		// 直接调用\Yii跳过use
		'/(?<!\\\\)Yii/' => '\Yii',
		// CHTML 全部调整成 \yii\helpers\Html
		'/(?<!\\\\)CHTML/ims' => '\yii\helpers\Html',
		// 所有短标签自动补充成<?php
		'/\<\?(\s)/' => '<?php\\1',
		// post请求判断切换成yii2形式判断
		'/isPostRequest/' => 'isPost',
		'/getIsPostRequest\s*\(\s*\)/' => 'isPost',
		// user->setState 在新版本中已经被取消
		'/user\-\>setState/' => 'session\-\>set',
		// 统一当前登录用户获取用户id
		'/\>\_id/' => '>getId ()',
		// 所有原参数获取,调整为默认获取
		'/getParam\s*\(\s*?([\'\"\w]+)[^\)]*?\)/ims' => '$_REQUEST[\\1]',
		// '/render\s*\(/' => 'renderPartial(',
		// 渲染页面动作需要进行返回
		'/\n(\s*)\$this\-\>render/' => '
\\1return $this->render',
		// 统一当前登录用户获取用户id
		'/user\-\>\_id/' => 'user->getId()',
		// getAttributes()不能带false参数, 不然会导致出错
		'/getAttributes\s*\(\s*false\s*\)/' => 'getAttributes()',
		// ;;去除无效代码,但是for(;;)需要绕过
		'/(?<!\()\;\s*\;/' => ';',
		// 补充表前缀
		'/\{\{(?=\w)/' => '{{%',
		'/findByPk/i' => 'findOne',
		// 所有数组修改成新形式
		'/(?<!\w)array\s*\(([^\(\)]*?)\)/ms' => '[\\1]',
		'/jquery\-easyui\-1\.2\.5/ims' => 'jquery-easyui-1.3.1',
		'/public\s*function\s*tableName/ims' => 'public static function tableName',
		'/getAction\s*\(\)/' => 'action',
		// load为默认函数,不可用该函数名,全部调整为loadModel
		'/([\s\>])load\s*\(/' => '\\1loadModel(',
		// 修改http异常,并直接引用
		'/CHttpException/' => '\yii\web\HttpException',
		// 修改ar继承类
		'/extends CActiveRecord/' => 'extends \yii\db\ActiveRecord',
		// 修改注释,用于引入框架时,实现代码提示
		'/CActiveRecord/' => 'ActiveRecord',
		'/action\-\>getId\s*\(\)/' => 'action->id',
		'/getController\s*\(\)/' => 'controller',
		'/controller\-\>getId\s*\(\)/' => 'controller->id',
		'/getModule\s*\(\)/' => 'module',
		'/module\-\>getId\s*\(\)/' => 'module->id',
		// array 引用
		'/require\_once\s*\(\s*[\'\"]array\.php[\'\"]\s*\)\;/ims' => 'lib(\'array.php\');',
		'/require\_once\s*\(\s*[\'\"]array2\.php[\'\"]\s*\)\;/ims' => 'lib(\'array2.php\');',
		// 去除WebControls引用
		'/require\_once\s*\(\s*[\'\"]WebControls\.php[\'\"]\s*\)\;/' => '',
		// 直接调用WebControls
		'/new WebControls/' => 'new \ext\WebControls',
		// 去除MysqlTools引用
		'/require\_once\s*\([\'\"]MysqlTools\.php[\'\"]\)\;/' => '',
		'/lib\s*\(\s*[\'\"]MysqlTools\.php[\'\"]\s*\)\;/' => '',
		// 直接调用MysqlTools
		'/(?<!\\\\)MysqlTools/' => '\ext\MysqlTools',
		// GCheckData直接转化
		'/(?<!\\\\)GCheckData/' => '\ext\GCheckData',
		// 替换控制器集成类
		'/extends\s*CController/' => 'extends \yii\web\Controller',
		// beforeAction只能为公开函数
		'/protected\s*function\s*beforeAction/ims' => 'public function beforeAction',
		// 判断到有beforeAction的,需要进行父函数调用,否则会导致过滤器失效
		'/beforeAction/' => function ($path, $content) {
			// 有使用before,但是没有进行父函数调用,需要补充父类beforeAction调用
			if (! preg_match ( '/parent\:\:beforeAction/', $content )) {
				$content = preg_replace ( '/beforeAction[^\{]+?\{/ims', 'beforeAction($action) {
		// 需要调用父函数,否则不会触发过滤器
		if (!parent::beforeAction ( $action )) {
			return false;
		}', $content );
			}
			return $content;
		},
		// 整个替换module.php内容,不然配置文件需要手动修改.
		'/CWebModule/' => function ($path, $content) {
			$namespace = getNamespaceByPath ( $path );
			$content = <<<EOF
<?php
namespace {$namespace};
class Module extends \yii\base\Module {
	public function init() {
		parent::init ();
	}
}
EOF;
			return $content;
		},
		// ar特殊处理,补充命名空间
		// 需要先进行命名空间的添加,用于控制器,页面添加对象时,直接识别命名空间,并添加
		'/\\\\yii\\\\db\\\\ActiveRecord/' => function ($path, $content) {
			$namespace = getNamespaceByPath ( $path );
			// \s和(?!)正向零宽断言会导致误判,需要后面补充一个标志
			if (! preg_match ( '/^\<\?php\s*namespace/is', $content )) {
				$content = preg_replace ( '/^\<\?php\s*/ims', "<?php\nnamespace {$namespace};\n", $content );
			}
			// ArticleX 的model有特殊实现,不进行替换.
			if (! preg_match ( '/ArticleX/', $path ) && preg_match ( '/function\s*model\s*\(/ims', $content )) {
				$content = preg_replace ( '/function\s*model\s*\([^\}]+?\}/ims', 'function model($className = __CLASS__) {
		return new self ();
	}', $content );
			}
			if (preg_match ( '/function\s*getList\s*\(\s*\$criteria\s*\=\s*null/ims', $content )) {
				$content = preg_replace ( '/function\s*getList\s*\(\s*\$criteria\s*\=\s*null\s*/ims', 'function getList($afmodel = null', $content );
				$content = preg_replace ( '/(function\s*getList\s*\(\s*\$afmodel\s*\=\s*null\s*[^\;]+?)\$this\-\>findAll\s*\(\s*\$criteria\s*\)\s*\;/ims', '\\1$afmodel->all();', $content );
			}
			if (preg_match ( '/function\s*getCount\s*\(\s*\$criteria\s*\=\s*null/ims', $content )) {
				$content = preg_replace ( '/function\s*getCount\s*\(\s*\$criteria\s*\=\s*null\s*/ims', 'function getCount($afmodel = null', $content );
				$content = preg_replace ( '/(function\s*getCount\s*\(\s*\$afmodel\s*\=\s*null\s*[^\;]+?)\$this\-\>count\s*\(\s*\$criteria\s*\)\s*\;/ims', '\\1$afmodel->count();', $content );
			}
			return $content;
		},
		// 控制器特殊处理,补充命名空间,修改过滤器
		'/\\\\yii\\\\web\\\\Controller/' => function ($path, $content) {
			$namespace = getNamespaceByPath ( $path );
			$models_namespace = getNamespaceByPath ( dirname ( $path ) ) . '\\models';
			
			// 修改过滤器
			// 其它特殊模块,照样修改
			if (preg_match ( '/public\s*function\s*filters\(\s*\)\s*\{[^}]+?\}/ims', $content )) {
				$string = <<<EOF
public function behaviors() {
		return [ 
				'access' => [ 
						'class' => \\ext\\RbacFilter::className () 
				] 
		];
	}				
EOF;
				$content = preg_replace ( '/public\s*function\s*filters\(\s*\)\s*\{[^}]+?\}/ims', $string, $content );
			}
			// 先获取ar列表,并添加到use中,再添加命名空间
			// 获取所有ar,并标记到use中和页面中
			$models = getModelsByControllerPath ( $path );
			$use_models = array ();
			foreach ( $models as $model ) {
				$model_ns = $models_namespace . '\\' . $model;
				// 判断是否有该类同时判断是否已添加命名空间
				if (preg_match ( "/\W{$model}\W/ms", $content ) && ! stristr ( $content, $model_ns )) {
					$content = preg_replace ( '/^\<\?php\s*/ims', "<?php\nuse \\{$model_ns};\n", $content );
					$use_models [] = $model;
				}
			}
			// 控制器补充命名空间使用
			// \s和(?!)正向零宽断言会导致误判,需要后面补充一个标志
			// 命名空间前面不能直接加反斜杠,use 前可以
			if (! preg_match ( '/^\<\?php\s*namespace/ims', $content )) {
				$content = preg_replace ( '/^\<\?php\s*/ims', "<?php\nnamespace {$namespace};\n", $content );
			}
			// 页面补充命名空间使用
			$views = getViewsByControllerPath ( $path );
			foreach ( $views as $view ) {
				$page_content = file_get_contents ( $view );
				// 去除头部和尾部空白部分
				$page_content = trim ( $page_content );
				// 如果没有php头,就补充php头
				if (preg_match ( '/^(?!\<\?php\s*)/i', $page_content )) {
					$page_content = preg_replace ( '/^(?!\<\?php\s*)/i', '<?php

?>', $page_content );
				}
				$use_models = array ();
				foreach ( $models as $model ) {
					$model_ns = $models_namespace . '\\' . $model;
					// 判断是否有该类同时判断是否已添加命名空间
					if (preg_match ( "/\W{$model}\W/ms", $page_content ) && ! stristr ( $page_content, $model_ns )) {
						$page_content = preg_replace ( '/^\<\?php\s*/is', "<?php\nuse \\{$model_ns};\n", $page_content );
					}
				}
				file_put_contents ( $view, $page_content );
			}
			return $content;
		},
		// $criteria =new CDbCriteria 及分页逻辑实现自动转化
		'/\$criteria\s*\=\s*new\s*CDbCriteria.+?(\$this|\$model|\w+|\w+\:\:model\s*\(\s*\))\-\>(findAll|find|getList)\s*\([^\;]*?\)\;/ims' => function ($path, $content, $preg) {
			while ( preg_match ( $preg, $content, $matchs ) ) {
				$subcontent = $matchs [0];
				$object = $matchs [1];
				// 如果是xxx::model()和$this ,需要对(:,(,),$)补充斜杠,进行转义处理,用于正则表达式
				if (preg_match ( '/([\:\(\)\$])/', $object )) {
					$preg_object = preg_replace ( '/([\:\(\)\$])/', '\\\\\\1', $object );
				}
				// 调试识别结果
				// gddebug ( $preg_object, $object, $subcontent, $matchs );
				// exit ();
				// 原CDbCriteria编程ActiveQuery形式,直接通过find返回该对象,取代.
				$subcontent = preg_replace ( '/\$criteria\s*\=\s*new\s*CDbCriteria\s*(\(\s*\))?\;/ims', "\$afmodel=(\$afmodel?\$afmodel:{$object}->find());", $subcontent );
				// CDbCriteria condition 转化,全部通过andWhere代替,重叠部分,会自动补充and处理
				$subcontent = preg_replace ( '/\$criteria\s*\-\>condition\s*\.?\s*\=\s*([^\;]+?)\;/ims', "\$afmodel->andWhere(\\1);", $subcontent );
				// CDbCriteria addCondition 转化,全部通过andWhere代替,重叠部分,会自动补充and处理
				$subcontent = preg_replace ( '/\$criteria\s*\-\>addCondition\s*\(([^\;]+?)\)\;/ims', "\$afmodel->andWhere(\\1);", $subcontent );
				// CDbCriteria order 转化
				$subcontent = preg_replace ( '/\$criteria\s*\-\>order\s*\.?\s*\=\s*([^\;]+?)\;/ims', "\$afmodel->orderBy(\\1);", $subcontent );
				// CDbCriteria select 转化
				$subcontent = preg_replace ( '/\$criteria\s*\-\>select\s*\.?\s*\=\s*([^\;]+?)\;/ims', "\$afmodel->select(\\1);", $subcontent );
				// ActiveRecord count 转化
				$subcontent = preg_replace ( '/' . $preg_object . '?\s*\-\>count\s*\([^\;]*?\)\;/ims', "\$afmodel->count();", $subcontent );
				
				// 如果出现特殊自定函数,修改传入参数
				$subcontent = preg_replace ( '/\-\>getCount\s*\(\s*\$criteria\s*\)/', '->getCount($afmodel)', $subcontent );
				
				// CPagination分页对象转化
				$subcontent = preg_replace ( '/new\s*CPagination\s*\(([^\)]+?)\)/ims', 'new \yii\data\Pagination ( [ 
				"totalCount" => \\1
		] )', $subcontent );
				// 分页大小转化
				$subcontent = preg_replace ( '/\$pages\s*\-\>\s*pageSize\s*\=([^\;]+)\;/ims', "\$pages->setPageSize ( \\1 );", $subcontent );
				// $pages->applyLimit($criteria) 没用,替换成page变量设置及分页变量带入ActiveQuery处理
				$subcontent = preg_replace ( '/\$pages\s*\-\>\s*applyLimit([^\;]+)\;/ims', "\$pages->setPage ( \$page-1 );
			\$afmodel->offset ( \$pages->offset )->limit ( \$pages->limit );", $subcontent );
				// ActiveRecord::findAll转化成 ActiveQuery::all()
				$subcontent = preg_replace ( '/' . $preg_object . '\s*\-\>(findAll|find\s*\(\s*\)\-\>)\s*\([^\;]*?\)\;/ims', "\$afmodel->all();", $subcontent );
				// $model->getList进行特殊处理
				$subcontent = preg_replace ( '/' . $preg_object . '\s*\-\>getList\s*\([^\;]*?\)\;/ims', "{$object}->getList(\$afmodel);", $subcontent );
				// 所有andWhere 内多余的and进行剔除
				$subcontent = preg_replace ( '/andWhere\s*\(\s*(\'|\")\s*and/ims', 'andWhere(\\1', $subcontent );
				// 调试转化结果
				// gddebug ( $subcontent );
				// exit ();
				$content = str_replace ( $matchs [0], $subcontent, $content );
			}
			return $content;
		},
		'/(url\(\'\w+\'\)\?\>)\/(\w+)\//ims' => '\\1&\\2=',
		// 原find(where)调整成find()->where(where)->one()
		'/\-\>find\s*\(([^\)]+)\)/ims' => '->find ()->where (\\1)->one ()',
		// 原findAll(where)调整成find()->where(where)->all()
		'/\-\>findAll\s*\(([^\)]+)\)/ims' => '->find ()->where (\\1)->all ()',
		// count 替换成 find()->where()->count();
		'/\-\>count\s*\(([^\)]+)\)/ims' => '->find ()->where (\\1)->count ()',
		// deleteByPk转化成findOne()->delete();
		'/\-\>deleteByPk\s*\(([^\)]+)\)/ims' => '->findOne(\\1)->delete ()',
		// 页面url自动转化成全小写
		'/(?:\W)url\s*\(\s*\'[^\']+\'/ims' => function ($path, $content) {
			$content = preg_replace_callback ( '/url\s*\(\s*\'[^\']+\'/ims', '_strtolower', $content );
			return $content;
		},
		// 控制器,动作,只首字母大写,后半部分全部小写
		'/function\s*action(\w)\s*\(\s*\)/ims' => function ($path, $content) {
			$content = preg_replace_callback ( '/function\s*action(\w+)\s*\(\s*\)/ims', '_ucfirst', $content );
			return $content;
		} 
);
function _strtolower($matches) {
	return strtolower ( $matches [0] );
}
function _ucfirst($matches) {
	$action = strtolower ( $matches [1] );
	// actions 为过滤器配置,不进行过滤处理
	if ($action === 's') {
		return 'function actions()';
	}
	return 'function action' . ucfirst ( $action ) . '()';
}
function getModelsByControllerPath($path) {
	$models_dir = dirname ( dirname ( $path ) ) . '/models';
	$list = FileTools::getCurList ( $models_dir );
	if (! $list)
		return array ();
	$items = array ();
	foreach ( $list as $item ) {
		$filename = basename ( $item );
		$classname = str_replace ( '.php', '', $filename );
		$items [$classname] = $classname;
	}
	return $items;
}
function getViewsByControllerPath($path) {
	$ctlName = basename ( str_replace ( 'Controller.php', '', $path ) );
	$ctlName = strtolower ( $ctlName );
	$models_dir = dirname ( dirname ( $path ) ) . '/views/' . $ctlName;
	$list = FileTools::getCurList ( $models_dir );
	if (! $list)
		return array ();
	$items = array ();
	foreach ( $list as $item ) {
		$filename = basename ( $item );
		$classname = str_replace ( '.php', '', $filename );
		$items [$classname] = $item;
	}
	return $items;
}
function getNamespaceByPath($path) {
	global $root_path;
	$path = dirname ( $path );
	$path = preg_replace ( '/\//', '\\', $path );
	return str_replace ( $root_path, '', $path );
}
// sql 中,pow需要手动检查,替换成 power ,pi 需要手动检查,替换成 acos(-1)

$preg_file = array (
		'/^\w+Module\.php$/' => 'Module.php' 
);
FileTools::replacenames ( $path, $preg_file );
FileTools::replaceContents ( $path, $preg_contents, array (
		'/\.php$/i' => false,
		'/yiic/i' => true 
) );

//直接根据列表文件进行替换规则处理


 

模块自动转化工具

/yii2sys/_cover_tools/replacefile_to_yii2.php
通过配置指定目录,脚本可实现yii1绝大部分自动转换到yii2形式
主要区别
yii2补充命名空间
工具已实现页面和控制器,自动引入models相关类,model类和控制器自动追加命名空间
全局类引入,非常用类型,直接以\yii\xxx 或\ext\xxx形式带入,减少不必要引入代码
rbac
基本和yii1相同,但是一些数据字段名做了调整(如:adminid调整为admin_id,很多类似字段都补充了下划线)
ar的查询方式
通过find的形式返回ActiveQuery对象,通过对该对象进行操作实现查询
原 CDbCriteria 对象被取消,工具已实现常用查询类的自动转化,关联查询仍然需要进行手动补充调整.
关联查询,通过配置查询对象,实现分页,主要特殊在主表和子表重命名,具体看项目案例.
分页对象做了调整,默认$_GET[‘page’]不做为默认分页值,需要手动设置
系统结构调整
/system 原模块被整合到/app/modules/里
框架结构
/yii2framework
使用yii2高级模板,已做结构的调整同时项目yii2sys也做了调整,使现有结构形式按原来的部署方式
(注:有需要可自行下载原高级模板进行了解)
编辑器使用
为实现快速开发,所有有ar返回的函数,函数注释可以通过补充@return ActiveRecord 实现代码提示(需要在inlucde_path中引入框架做为附属项目)
主要修改点整理:
url() yii2fix module 默认会到根当成模块
导致顶根判断异常,所以需要跳过
自定义state
yii2已移除state,官方说法是避免混乱.导致无法同域名多应用session共享冲突
md5版本
可以实现端口共享session
域名+目录+程序id版本
实现多项目时,自动区分session数据
\Wechat 类第三方重写,可能类很多,编写时,统一全部认根域名.实现快速重写
HeadersAlreadySentException 异常
// ini_set ( ‘output_buffering’, 0 );设置无效,还是需要通过修改配置.不然超出会抛
__CLASS__ 会带入命名空间路径
php 7.2 下 upload 上传兼容 media data missing hint 异常
兼容方式为 curl_file_create 形式
Yii2 已 去除任意参数 路径化处理.
需要路径化的参数,只能通过配置实现. 前台除了控制器经过重写外,其它参数全部都以 ? 形式拼接
\yii\helpers\Html::DropDownList 不再自动代入id,需要通过htmloptions配置进去
CHtml 调整成 Html
CWenhaoPager.php 重写成 LinkPager 形式
反射类调用,需要写全命名空间
计划任务
表前缀 {{%table_name}} 多了个 “%”
入口环境 测试环境(保留) 开发环境 ,生产环境 切换
将/system 移动到 app/modules/system 做为 app 下的模块
Yii::$app->createUrl 换成 Yii::$app->urlManager->createUrl
CDbCriteria
$models = (new \app\modules\system\models\Menu ())->find ()->where ( “parentId=0 and state=1” )->orderBy ( ‘ordernum asc,id asc’ )->all ();
ar 修改成yii2形式,需要实现接口继承+覆盖几个内置函数
$model->getAttributes ( false ); false 去掉 ,默认动作只识别null
Yii::$app->request->isPostRequest 替换成 Yii::$app->request->post ()
Yii::$app->controller->getAction ()->getId () Yii::$app->controller->action->id
Yii::$app->controller->getId () Yii::$app->controller->id
Yii::$app->controller->getModule () Yii::$app->controller->module->id
controllers 控制器 render 类动作,需要返回. 变成 return $this->render…
enableCsrfValidation 全局.暂时csrf校验关闭,默认开启.动作在action之前
后台基本版 igd_system_adminauthassignment 表 userid 调整为 user_id (框架写死字段)
beforeAction 不能直接返回true,需要调用父函数,否则会导致过滤器无法触发
数据库权限判断 app ()->authManager->checkAccess ( $user_id, $permission ) 参数顺序变化
表重命名
AdminLog::model ()->find ()->alias ( ‘t’ );
表链接
AdminLog::model ()->find ()->innerJoinWith ( [
// 关联表,重命名
‘admin as a’
] )
http 异常抛出调整
throw new CHttpException ( 404, ‘The ‘ . __CLASS__ . ‘ does not exist.’ );
throw new \yii\web\HttpException ( 404, ‘The ‘ . __CLASS__ . ‘ does not exist.’ );
动态表限制实在太多.后续有需要,需要通过ArticleX->fixTableName进行修正
原find(where)调整成find()->where(where)->one()
原findAll(where)调整成find()->where(where)->all()

再次占位置,一年份的博客

key 长度 32 位处理 aes-256-xxx
mcrypt_module_open ( MCRYPT_RIJNDAEL_128, ”, MCRYPT_MODE_CBC, ” )
mbstring.func_overload 重载,导致 str*功能异常问题
pecl install mcrypt-snapshot
7.2.x 强制安装扩展
屏蔽 is DEPRECATED
error_reporting(E_ALL ^ E_DEPRECATED);
反向代理,REMOTE_ADDR 设置真实ip
chrome 扩展,页面通讯
页面另存成图片
html2canvas
远程图片跨域设置
_img.setAttribute(‘crossOrigin’, ‘anonymous’);
画布绘制
原型头像
位置修改
以下ID的密钥没有可用的公钥
sudo apt-key adv –keyserver keyserver.ubuntu.com –recv-keys
依赖… 但是它将不会被安装
Aptitude
jquery plugin 插件编写
继承
win 客户端走代理
通过cmd
set proxy=http://127.0.0.1:1080
SET HTTP_PROXY=%proxy%
SET HTTPS_PROXY=%proxy%
Kitematic.exe
php excel 图片插入+适应
yii2版本动态AR
阿里云
/etc/yum.repos.d/pel被强制跳转镜像源
超大文件断点续传
跟踪端口网络
nmap
nmap -p 80 -Pn –traceroute xxxxxxx
traceroute
素材图片转化
ppt,pptx
jodconvert
ai,psd,pdf
convert
convert *.psd[0] *.png
cdr
uniconvert
配合python进行安装,centos下,需要通过pip将所有模块安装完成
mp4,mov,avi
ffmpeg
取指定时间
创建无法执行命令的ftp账户
直接修改/etc/passwd
usermod loginname -s /sbin/nologin
pure-ftpd 默认修改密码对应不上,需要通过passwd 进行密码修改
workerman 整合yii
小程序可直接使用web-msg-sender做为web-view内使用,无需走wss处理,网页端,可直接ws,已测试.
走http协议,可以绕过小程序的检查,设置端口执行websocket
Gateway
yii 端通过调用客户端,实现消息推送
通过dbsession+sessionid传递,实现会话数据共享
Gateway event类,通过将所有消息以http形式反馈给yii控制器.由yii控制器实现逻辑代码
gateway 用curl 会报错,直接通过file_get_contents 加超时处理.
ppt 转 pdf 兼容 msoffice
openoffice 等开源工具都不兼容,只能通过wps(通过python脚本),但是wps目前只发现win下有开放,linux下安装后,没看到接口
python 调用 wps 进行ppt兼容转pdf, win32client处理
新概念四学到第20课
php exec 运行soffice 相关命令无返回
2>&1 屏幕输出内容(包括异常)全部进行反馈
rc.local 启动运行,所有命令补充”&”标记,变成后台运行,防止一个出错,导致后续脚本异常
svn hook 同步中文修复
不然.svn里的数据库会出错
linux 下 java -jar 中文编码异常
java -Dfile.encoding=UTF-8 -Dsun.jnu.encoding=UTF-8 -jar *.jar
小程序代理发布
小程序,web-view 真实手机端调试,基本无解
只能通过weinre 进行脚本注入
最便宜的开发测试机
iphone4s 支持ios8 ,可安装新版本微信,可运行调试小程序;iphone4不行
yii autoload_unregister 状态下异常抛出混乱处理,如phpexcel等操作器
手动引入
@YiiBase::autoload ( ‘CHttpException’ );
@YiiBase::autoload ( ‘CExceptionEvent’ );
win7 系统 sfc 修复
can not repair member .. 直接通过win10升级助手搞定,可保留原程序和原文件.
微软拼音
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\CTF\TIP\{81d4e9c9-1d3b-41bc-9e6c-4b40bf79e35e}
SoapClient
代理抓包
$params = array (‘trace’ => 1,’exceptions’ => 1,’soap_version’ => SOAP_1_1,’proxy_host’ => ‘xxx’, ‘proxy_port’ => ‘xxxx’,’stream_context’ => stream_context_create ( [ ‘http’ => array (‘proxy’ => “http://xxx:xxx”,’request_fulluri’ => true,”method” => “POST” ) ] ));
$client = new SoapClient ( ‘http://xxxx’, $params );
请求响应打印
json_encode 不编码中文
微信接口相关
JSON_UNESCAPED_UNICODE

easyui 插件规范 编写 倒计时demo

/*******************************************************************************
 * @author caihaibin <243008827@qq.com>
 * @version 1.1.1 
 *******************************************************************************/
(function($) {

	function getTxt(target) {
		if($(target).prop("tagName") == 'INPUT') {
			return $(target).val();
		} else {
			return $(target).html();
		}
	}

	/**
	 * 根据按钮类型,自动识别文本字段来自value还是html
	 * @param {targetect} target
	 */
	function setTxt(target, txt) {
		if($(target).prop("tagName") == 'INPUT') {
			//恢复文本
			$(target).val(txt);
		} else {
			//恢复文本
			$(target).html(txt);
		}
	}
	/**
	 * 停止计时器
	 */
	function stop(target) {
		//恢复按键文本
		setTxt(target, $.data(target, 'countdown').data.text);
		//恢复点击
		$(target).removeAttr('disabled');
		//清除计时器对象
		clearInterval($.data(target, 'countdown').data.time_id);
	}

	function bindEvents(target) {
		//绑定点击事件
		//click.xxx为命名空间形式,可以通过unbind('.xxx')一次性解除所有该命名空间下的绑定
		//取消原".countdown"命名空间下,所有绑定事件
		$(target).unbind('.countdown');
		//直接绑定新事件
		$(target).bind('click.countdown', function() {
			var time = $.data(target, 'countdown').options.time;
			//禁止二次点击
			$(target).attr('disabled', 'disabled');
			//获取计时器标志(int类型)
			var time_id = setInterval(function() {
				if(time <= 0) {
					//统一调用计时器插件结束动作
					$(target).countdown('stop');
					$.data(target, 'countdown').options.onEnd();
					return;
				}
				$.data(target, 'countdown').options.onShowtime(target, time, time + '秒');
				//显示倒计时结果
				setTxt(target, time + '秒');
				time--;
			}, 1000);
			//记录计时器标志到对象数据中,用于计时结束时,clear动作
			$.data(target, 'countdown').data.time_id = time_id;
		});
	}

	/**
	 * 初始化计时器插件
	 * @param {Object} options
	 */
	function create(target) {}
	/**
	 * parse options from markup.
	 */
	function parseOptions(target) {
		var t = $(target);
		return $.extend({}, {
			//如果参数内容为空或undefined,不会覆盖前面的内容.如果有值,依次会覆盖前面数组的具体键值
			time: t.attr('time') ? t.attr('time') : undefined
		});
	}
	$.fn.countdown = function(options, param) {
		if(typeof options == 'string') {
			var method = $.fn.countdown.methods[options];
			if(method) {
				return method(this, param);
			}
			$.error('Method ' + options + ' does not exist on jQuery.countdown');
		}
		options = options || {};
		return this.each(function() {
			//实现针对每元素级的函数和变量
			var state = $.data(this, 'countdown');
			if(state) {
				//二次初始化,只覆盖变量,重新绑定事件等..
				$.extend(state.options, options);
			} else {
				state = $.data(this, 'countdown', {
					//该对象所有选项,包括配置参数,传入配置,都存放在options
					//如果参数内容为空或undefined,不会覆盖前面的内容.如果有值,依次会覆盖前面数组的具体键值
					options: $.extend({}, $.fn.countdown.defaults, parseOptions(this), options),
					//该对象所有临时变量
					data: {
						//按钮文本内容,用于复原
						text: getTxt(this),
						//计时器标志,用于clear时,触发
						time_id: 0
					}
				});
			}
			//创建元素,只针对元素部分的调整.需要区分事件和元素的操作
			create(this);
			//绑定相关事件,可重复绑定;重复绑定时,通过事件命名空间进行解除
			bindEvents(this);
		});
	};
	//开放给外部调用动作
	//注:函数内部需要二次调用闭包中所定义函数,jq对象为数组,请求的闭包中的函数动作是单体.
	$.fn.countdown.methods = {
		//解析出参数配置
		parseOptions: function(jq) {
			//参数只需要一份,列表对象中参数相同,所以只需要返回首个
			return parseOptions(jq[0]);
		},
		//返回所配置参数
		options: function(jq) {
			//参数只需要一份,列表对象中参数相同,所以只需要返回首个
			return $.data(jq[0], 'countdown').options;
		},
		//停止计时动作
		stop: function(jq) {
			return jq.each(function() {
				stop(this);
			});
		}
	};
	//外部参数配置,允许参数和函数事件等
	$.fn.countdown.defaults = {
		/**
		 * 默认时长
		 */
		time: 60,
		/**
		 * 计时事件
		 * @param {Object} target
		 * @param {Object} time 当前秒数
		 * @param {Object} txt 秒数文本
		 */
		onShowtime: function(target, time, txt) {},
		/**
		 * 结束事件
		 * @param {Object} target
		 */
		onEnd: function(target) {}
	};
})(jQuery);
<!DOCTYPE html>
<html>

	<head>
		<title>计时器测试</title>
		<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
		<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0">
		<meta name="apple-mobile-web-app-capable" content="yes">
		<meta http-equiv="pragma" content="no-cache">
		<meta http-equiv="cache-control" content="no-cache">
		<meta http-equiv="expires" content="0">
		<script src="scripts/jquery.js"></script>
		<script src="scripts/jquery.countdown.js"></script>
	</head>

	<body>
		<button time="3">3秒倒计时</button>
		<button onclick="$('button[time]').countdown('stop')">取消倒计时</button>
		<input type="button" value="60秒倒计时">
		<button onclick="$('input[type=button]').countdown('stop')">取消倒计时</button>
		<a time="3">a倒计时</a>
		<script>
			$(function() {
				$('input[time],button[time]').countdown({
					onShowtime: function(target, time, txt) {
						console.log(time, txt);
					},
					onEnd: function(target) {
						console.log('end');
					}
				});
				$('a[time]').countdown();
				//				$('a,button,input').css('pointer-events', 'none');
			})
		</script>
	</body>

</html>

 

新概念三完

三终于完成了,但还是要找时间回头复习,继续巩固熟练

再花一年搞定4,然后再集中花时间锻炼发音听力,最后就是广泛阅读.

想想现在好像没什么变化,起码沟通还凑合吧…上连接,github上问问题,朋友群里,英文沟通也凑合.速度不快.

https://github.com/yiisoft/yii/issues/4182

现在只要有时间就看,生活的杂事还是那么多,不过现在花更多的时候,也更集中.看到晚上2点.中午也看,周末也看.早上为了不影响早上的工作,早上睡醒就去上班.

再努力一年~ !

工作博客的,后面都只记录标题了.都是解决过的问题…通过标题应该能回忆起解决流程…

 

占下位置…两年份博客….

待写博客
tvmao
python
新概念35
des java 填充处理
htmlpurifier img src base64
java 文件流输出处理.
dcloud 云打包
ios打包
http://wenku.baidu.com/course/view/1ce3571252d380eb62946d8c
数据库,容易出现 not allow null 设置
脑图工具
update limit  number 类型 ” = 0
补充个 requestjs 特殊处理,兼容原来相关插件代码(取消jquery引入,防止变量和绑定相关覆盖)
dclound自动更新
dcloud 拍照上传
 iphone 设备,图片旋转排查处理
jquery.autocomplete 加将一些特殊功能触发 ,做了不好几个小地方的特殊修改)  中文自动输入补全bug,详细见描述
http://xxxxx/wcf/kuandaisearch
订单支付,需要补充前缀.
多边形,区域识别
mac 发布
ios 各种版本差别
eclipse 奇怪异常 ,最新版本, 不兼容jdk1.8以下的版本 xp 不支持1.6以上版本,所以只能临时用笔记本处理.然后找时间升级操作系统.
eclipse 只单独切换没用,需要操作系统环境进行切换.
adt  切换 android版本到 6.x
The method requestPermissions(String[], int) is undefined for the type
虚拟机安装ios 10.11  (usb 切换到2.0 才能进行手机远程调试 3.0 识别不到设备)
php 安装 curl .
有道翻译插件.
oracle 跨数据库连接
vpn 兼容局域网.
http://www.cnblogs.com/Real_Dream/articles/1577889.html
metric  值为跳跃计数点,越高优先级越高
route add 192.168.1.0 mask 255.255.255.0 192.168.1.1 metric 5
多chrome
png全透明,无黑边,无锯齿处理
php curl cache
stackoverflow.com/questions/20552592/how-to-flush-php-curls-dns-cache
javascript [^]+? 匹配
javascript 替换 jquery大全.
php ftp 工具传大文件数据丢失问题.
app store 内购
// php 5.6 以上版本 默认变成 mb_strlen (string ,’utf-8′); 5.4还是默认 8bit
strlen php 5.6 得 mb_strlen (‘8bit’) 进行兼容
unionid  详解
type=”datetime-local”
微信集中access_token处理
新概念45课
fildder 抓取 php curl https 数据.
phantomjs
slimerjs
opencv
pytesseract 图像文字识别…
微薄模拟登录.模拟跳转.
模拟跳转.实现cookie激活
phantomjs cookie 转 php curl
php 3des
linux 安装 phantomjs
Eclipse中格式化Jquery代码+html+js代码.
png 穿透点击 模拟点击 对只针对目标对象
酷q
ss 安装
open.taobao.com 之沙箱.
chrome headless (字体) 采集chrome-remote-interface
nginx 路径转发
denyhosts 使用.
fonteditor-core fontmini fontkit
58字体破解
open_basedir简单用法
ifsvnadmin 密码方式异常(配置路径)
mobaxterm
svn hook 按目录更新
attempt to write a readonly database 异常
ffmpeg 转换 mov 旋转问题(3.x 以上正常,自动旋转)
mcrypt 在 php7.2下的实现.以及yii 1.x 加密模块的重写(官方不鸟…)

有道词典 谷歌插件优化版

效果图:

注:该插件是有道官方提供的,但是一些细节东西没处理好.提交了修改建议老是没鸟,就自己搞搞. 分享页面和相关功能进行了优化,有需要的朋友自便.不清楚的,再问我.

优化功能:

初始化,隐藏相关菜单,侧面菜单(觉得每次都要单独关闭一次,比较浪费时间).

最大化文本框(有道没有提供网页端的设置,客户端有).

粘贴富文本内容,自动过滤标签.保留回车符.

iframe 选中修复

默认字体+默认字体颜色进行设置(只有客户端能设置,但是客户端不兼容有道划词翻译[-.-#, 91 年的中年人了,老了,不看18px的字体,眼睛就不舒服,太鲜红的也不舒服~]).

补充滚动条记忆处理,刷新后,会自动滚动到最后的位置 (很容易出现因网络问题或服务器问题,导致网络链接断开[wifi下比较明显],会从头加载,对于长内容,每次找到目标都比较蛋碎…)

有道词典Chrome鼠标取词插件_v2.5.0

下载上面的插件,解压到本地.

按设置,勾选”开发者模式”

chrome

并加载解压后的目录.

需要自动过滤html的,需要在链接后面补充  &fillhtml=1 标志,即分享页面后面追加即可

flag

默认字体+默认字体颜色进行设置

bulb.min.04731db4

解压上述文件.

ReRes_v1.8.1

解压,拖到插件管理页面,进行安装.

然后补充如下设置

plugin_set

http://note.youdao.com/editor/collab/bulbeditor/bulb.min.04731db4.js

file://e:/soft/editor/bulb.min.04731db4.js

上面解压后的文件路径.

比较懒,现在不想动.不然把东西写成一个 ,加按钮什么的也是可以的….    ( ̄︶ ̄) 胖子就这样子~

php urlencode 内容 java 输出图片

import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.util.Iterator;

import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;

public class test {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		String qrcode;
		try {
			//java的urldecode会指定编码,需要设置为iso-8859-1,这样输出的才是二进制
			qrcode = URLDecoder
					.decode("%89PNG%0D%0Axxxxxx",
							"ISO-8859-1");
			
			//以下为二进制内容输出为图片,不可以直接用普通方式输出图片,会导致文件头加了些东西,导致图片破坏

			ByteArrayInputStream bis = new ByteArrayInputStream(
					qrcode.getBytes());
			Iterator<?> readers = ImageIO.getImageReadersByFormatName("png");
			// ImageIO is a class containing static convenience methods for
			// locating ImageReaders
			// and ImageWriters, and performing simple encoding and decoding.

			ImageReader reader = (ImageReader) readers.next();
			Object source = bis; // File or InputStream, it seems file is OK

			ImageInputStream iis = ImageIO.createImageInputStream(source);
			// Returns an ImageInputStream that will take its input from the
			// given Object

			reader.setInput(iis, true);
			ImageReadParam param = reader.getDefaultReadParam();

			Image image = reader.read(0, param);
			// got an image file

			BufferedImage bufferedImage = new BufferedImage(
					image.getWidth(null), image.getHeight(null),
					BufferedImage.TYPE_INT_RGB);
			// bufferedImage is the RenderedImage to be written
			Graphics2D g2 = bufferedImage.createGraphics();
			g2.drawImage(image, null, null);
			File imageFile = new File("d://test.png");
			ImageIO.write(bufferedImage, "png", imageFile);
		} catch (UnsupportedEncodingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

	}

}

 

python 兼容 php urldecode 处理

#注意当前脚本是python 3.6.x
#!/usr/bin/python
# -*- coding: utf-8 -*-
import urllib,sys,re
import struct
#读取当前编码
print (sys.getdefaultencoding())
qrcode="xxxxxxxxxxxxxxxxxxxxxxxxxxx"
#php urlencode 同 python 的urlencode 差别是
#python的urldecode处理有两种 urllib.parse.unquote_plus 和 urllib.parse.unquote
#差别是 urllib.parse.unquote_plus 会将 "+" 调整为 " ".这是和php urldecode相同的方式
#但是普通urllib.parse.unquote处理会将内容进行编码,导致结果和要的冲突.文件本身已是二进制,直接读,写入就是文件,经过编码,文件就出问题

qrcode=qrcode.replace("+"," ")
#比较 plus 后的处理结果是否相同
print (urllib.parse.unquote(qrcode)==urllib.parse.unquote_plus(qrcode))
#原内容长度
print (len(qrcode))
#获取二进制内容长度,用于判断是否有漏缺
print (len(urllib.parse.unquote_to_bytes(qrcode)))
#将处理后的内容写入文件
file=open("test.png","wb")
file.write(urllib.parse.unquote_to_bytes(qrcode))
file.close();