Skip to content

一个根据ruoyi-vue改造而来的超轻量级的PHP后台框架,php版本的、简化版的、若依前后端分离版的后台管理系统。

Notifications You must be signed in to change notification settings

netwolf712/ry-php

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

7 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

引言

一个超轻量级的PHP后台框架,由开源框架 MINICodeIgniter 结合而成。基本框架为MINI,但是数据库引擎用的是CodeIgniter。

怎么说呢,看重的是MINI的超轻量级,但感觉数据库部分又太过于简单了,所以又从CodeIgniter挖了部分过来,希望这是个正确的选择吧。

做这个项目的起因是因为一直在用一个很著名的前后端分离项目 若依 做一些小项目,因为基本的用户管理功能都有了,只要做业务就行,很是便利。

但是随着项目增多就发现java太耗资源了,一个简单的小项目,没什么访问量,但是内存、CPU都会被吃掉一大堆,随着部署的项目增多,服务器就会不堪重负。像我们这种做小项目的,本身就没几块钱,如果一个项目搞一个服务器,那后面服务器的维护成本就会不堪重负。所以想着能否搞个超轻量级的后台服务,前端还是用的ruoyi-vue的前端,基本数据库表也不用去动他,还是熟悉的配方,只是把后端语言变一下。于是就想到了php,由于本人主要是做C开发的,java算是第二语言,php就更差了,所以只能当个裁缝,四处拿过来缝缝补补,最终目的就是能用就行。

也因为白嫖了若依那么久,所以把这个开源出来,希望对大家有点帮助吧。

需求

  • PHP 5.3.0+、PHP7.4简单自测可用.
  • Redis 用于缓存用户session
  • MySQL
  • SQlite 支持SQLite是想着在嵌入式设备也能用起来,这样就不用装MySQL这些,进一步减少开销。实测在RK3308、S905x这些芯片上可用。 但这其实是个伪命题,主要是内存和flash空间占用的问题,都用上PHP、前后端分离(实测发现编译出来的前端空间也不小)了,这些flash空间占用都不小,再去省MySQL的空间是否还有必要?

目录说明

  • docs:存放一些文本文件 ry-php.postman_collection.json:后端接口说明,导入postman即可使用
  • ry-server:用php编写的后端代码
  • ry-ui:从ruiyi-vue 改造而来的前端代码,准备弃用,已完全支持ruoyi-vue最新版本(v3.8.6)的前端页面。建议大家直接下载ruoyi-vue的代码,直接拿ruoyi-ui目录的代码进行配套使用。
  • sql:数据库脚本 ry_php.db: SQLite数据库,在ry-server/application/config/database.php中配置正确的路径即可直接使用。 ry_php.sqlite:生成SQLite数据库的脚本,可通过SQLite工具导入生成所需的数据库 ry_php.sql:生成MySQL数据库的脚步,可通过MySQL工具导入生成所需的数据库
  • images:示例图片

web服务器部署举例

nginx服务器的部署配置

server {
        listen  80;
        listen  [::]:80;
        server_name  localhost;
        access_log off;
	
        client_max_body_size 40m;

        #charset koi8-r;

        #access_log  logs/host.access.log  main;

        location / {
            root   前端页面根目录/dist;
            index  index.html index.htm;
        }

        #跳转到php服务器
        location /prod-api/ {
            proxy_set_header Host $http_host;
            proxy_set_header X-Real-IP $remote_addr;
            proxy_set_header REMOTE-HOST $remote_addr;
            proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
            proxy_pass http://localhost:8088/;
        }

        #error_page  404              /404.html;

        # redirect server error pages to the static page /50x.html
        #
        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }
    }
#配置后端服务
server {
        listen  8088;
        server_name  phpServer;
        access_log off;
	    client_max_body_size 40m;


        location / {
            root   php源码根目录/public;
            #index  index.html index.htm index.php;
	        if (!-e $request_filename) 
            {                                 
               rewrite ^(/index.php|/index.php/|/)(.*)$ /index.php?$1 last;
               break;
            }
        }


        error_page   500 502 503 504  /50x.html;
        location = /50x.html {
            root   html;
        }

        #设置php代理,检测是.php结尾的文件时自动调用fastcgi,使之调用php解析程序,解析处理后返回结果
        location ~ \.php$ {
            root           php源码根目录/public;
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
            include        fastcgi_params;
            add_header X-Frame-Options SAMEORIGIN;
            #deny all;
            #allow all;
        }
      
}

更详细的Nginx配置教程,可以看它的官方网站 点击此处.

快速开始

前端介绍

前端从 ruiyi-vue 改造而来,只是后端接口路径做了部分修改,所以还是直接看若依的官方说明吧,已经写得很详细了,点击此处

后端介绍

  • 后端介绍中所有涉及到文件路径的都是基于ry-server目录下的相对目录

测试账号

admin/adin123

基本架构

应用程序的 URL 路径会直接转换为控制器及其内部方法 比如

URL路径:example.com/home/exampleOne 会执行application/controllers/home.php这个php文件里申明的exampleOne()函数。

URL路径:example.com/home 会执行application/controllers/home.php这个文件里申明的index()函数。

URL路径:example.com 会执行application/controllers/home.php这个函数里申明的index()函数 (缺省调用)。

URL路径:example.com/songs 会执行application/controllers/songs.php这个文件里申明的index()函数。

URL路径:example.com/songs/editsong/17 会执行application/controllers/songs.php这个文件里的editsong函数,并将17作为参数传递给它。

持久化数据库配置

数据库配置文件applicaition/config/database.php,通过改变dbdriver配置选择使用哪种数据库,当前时测支持MySQL和SQLite,数据引擎的封装代码为application/core。

MySQL配置举例

    $db['default']['hostname'] = '数据库URL';
    $db['default']['username'] = '数据库登录账号';
    $db['default']['password'] = '数据库密码';
    $db['default']['database'] = '数据库名';
    $db['default']['dbdriver'] = 'mysqli';  //MySQL的数据引擎
    $db['default']['dbprefix'] = '';
    $db['default']['pconnect'] = FALSE;
    $db['default']['db_debug'] = TRUE;
    $db['default']['cache_on'] = FALSE;
    $db['default']['cachedir'] = APPPATH.'cache/html';;
    $db['default']['char_set'] = 'utf8';
    $db['default']['dbcollat'] = 'utf8_general_ci';
    $db['default']['swap_pre'] = '';
    $db['default']['autoinit'] = TRUE;
    $db['default']['stricton'] = FALSE;

SQLite配置举例

    $db['default']['dbdriver'] = 'sqlite3'; //SQLite的数据引擎
    $db['default']['database'] = 'sqlite数据库存放位置';

缓存数据库配置

缓存数据库配置文件applicaition/config/redis.php,redis的封装代码路径为application/core/redis.php。

redis配置举例

    //默认缓存数据库
    $redis_config['redis_default']['host'] = '缓存数据库地址'; 
    $redis_config['redis_default']['port'] = '缓存数据库端口,默认为6379'; 
    $redis_config['redis_default']['password'] = '缓存数据库访问密码,可以为空'; 
    
    //从数据库,当实现redis分布式部署时才有用,尚未实测
    $redis_config['redis_slave']['host'] = '';  
    $redis_config['redis_slave']['port'] = '6379';  
    $redis_config['redis_slave']['password'] = ''; 

编写数据处理模型

在applicatoin/model增加数据处理的模型,比如sys_user.model,继承自application/core/model.php,基本的增删改查操作都已被model.php封装, sys_user.model只需封装跟业务相关的查询函数即可,比如

    public function validateUnique($username) {
		$adminInfo = $this->get('*', array("lower(user_name)"=>strtolower($username)));
		if ($adminInfo) {
		    return true;
		}

		return false;
	}

编写控制器代码

在applicatoin/controller/目录下增加控制器代码sys_user.php,在构造函数中将需要用到的模块引用进来,比如

    public function __construct($model_name) {
		parent::__construct($model_name);
        //引入sys_user数据模块
        $this->User_model = Helper::load_model("Sys_user",$this->db);
        ...
    }

在控制器中增加接口代码,比如

    /**
     * 获取登录用户的信息
     */ 
	public function getInfo(){
        //会话判断
		$user_id = $this->login_user_id;
		if (!$user_id) {
			printAjaxError('username', '会话已失效,请重新登录');
		}
        //获取用户信息
		$userInfo = $this->User_model->get("user_id as userId,user_name as userName,avatar",array('user_id'=>$user_id));
		if(!$userInfo ){
			printAjaxError('user_id', '用户不存在');
		}
		$userInfo['token'] = getEnUserId($this->redis);

		$userInfo['admin']=_is_admin($user_id);
		$permsList = array();

		$tmpPermsLIst = $this->_get_menu_permission($user_id);
		if($tmpPermsLIst){
			foreach($tmpPermsLIst as $key=>$value){
				if(isset($value['perms'])){
					array_push($permsList,$value['perms']);
				}else{
					array_push($permsList,$value);
				}
			}
		}
        //回复获取成功,将接口数据以application/json的形式返回给前端
		printAjaxRaw(array('code'=>200,'permissions'=>$permsList,'roles'=>$this->_get_role_permission($user_id),'msg'=>"操作成功",'user'=>$userInfo));
	} 

访问白名单配置

在application/core/application.php中集成了简单的访问过滤器fiter函数,当访问的url不在访问白名单内时,执行登录认证,若认证不通过,则返回403,默认除登录函数外,其他所有请求都需登录认证,若不需要认证,则在application/config/whitelist.php中将URL加入白名单列表即可。

// 白名单列表格式
// $whiteList[controller][method] = 1; //=非0,表示对应控制器的某个方法无须登录校验
// 比如
$whiteList['sys_user']['login'] = 1;

若依接口兼容

在application/config/ruoyimapper.php中增加了php版本的接口与若依前端接口的映射表,通过映射表可实现若依前端页面的零修改兼容,目的是方便大家实现后端服务器的平移替换,当php版本的不再满足需求时,可直接换回若依后端。

实现原理很简单,就是在application/core/application.php中实现了url请求转换函数convertRuoyiUrl,在真正解析url前,先把若依前端的url格式转换成php服务端相应请求的url格式。

映射表的配置规则举例

// ruoyiApiMapper为映射表
// 第一个键值为请求类型,如post、get、put、delete,要求为小写
// 后面的键值给请求url,比如前端页面的请求为 /system/user/list
// url中作为参数的部分不用作为键值
// 比如/system/user/1,其中的1对应/system/user/{userId},是作为userId这个参数,所以只需取/system/user即可
// 则第二个键值为system,第三个键值为user,第四个键值给list
// 映射的值为在php服务端的请求路径
// 比如前端页面的请求路径为/system/user/list,请求类型为get
// 对应的php服务端路径为sys_user/get_sys_user_list
// 则映射表表达式为
$ruoyiApiMapper['get']['system']['user']['list'] = "sys_user/get_sys_user_list";

// 不能存在路径完全一样的映射键值,假如出现前面几个键值完全一致时,则可以在后面再补增一个为index的键值
// 比如前端页面的请求路径为/system/user/1,请求类型为get
// 原先写成映射表达式为
$ruoyiApiMapper['get']['system']['user'] = "sys_user/get_sys_user_info";

// 但因['get']['system']['user']这部分键值与$ruoyiApiMapper['get']['system']['user']['list'] = "sys_user/get_sys_user_list";前面部分完全一致
// 所以需要改造成如下映射关系
$ruoyiApiMapper['get']['system']['user']['index'] = "sys_user/get_sys_user_info";

添加新表

如果给一张表添加基础的增删改查后端代码,可以参考sys_config表的实现过程,假设表名为sys_template

添加model

可参考application/model/sys_config_model.php,在application/model目录下增加一个与表名一致的model,比如sys_template_model.php

<?php
class Sys_template_model extends Model {

    // 将表字段重名为小驼峰模式,即去下划线_,将下划线后的第一个字母大写
    // 主要是为与java的表示方式一致
	private $_Vo = "template_id as templateId"
						.",create_by as createBy,create_time as createTime,update_by as updateBy,update_time as updateTime,remark";


    // 重载gets,主要是修改默认的排序方式
    public function gets($select = '*', $strWhere = NULL, $limit = NULL, $offset = NULL) {
		return $this->_gets($select,$strWhere,$limit,$offset,"template_id","asc");
	}

    // 重载gets2,主要是修改默认的排序方式
	public function gets2($strWhere = NULL, $limit = NULL, $offset = NULL)
	{
		return $this->_gets2($this->_configVo,$strWhere,$limit,$offset,"template_id","asc");
	}

    // 根据需要可定义更多的专有查询函数
}
添加controller

可参考application/controller/sys_config.php,在application/controller目录下增加一个与表名一致的controller,比如sys_template.php

<?php

class Sys_template extends Controller
{
    // 用户model
    private $User_model = NULL;
    // 业务model
    private $Sys_template_model = NULL;
    // 操作日志model
	private $Sys_oper_log_model = NULL;
    public function __construct($params) {
		parent::__construct($params);
        $this->User_model = Helper::load_model("Sys_user",$this->db);
        $this->Sys_template_model = Helper::load_model("Sys_template",$this->db);
		$this->Sys_oper_log_model = Helper::load_model("Sys_oper_log",$this->db);
    }

    /**
     * 列表查询接口
     * $jsonData 为url?prams形式param部分的数据对象
     */
	public function get_template_list($jsonData){
		$user_id = $this->login_user_id;
		if (!$user_id) {
			printAjaxError('username', '会话已失效,请重新登录');
		}
	
        //查询结果
		$count = $this->Sys_template_model->rowCount2($whereStr);
		printAjaxList($list,$count ? $count : 0);		
	}

    /**
     * 根据id获取详细的数据对象
     * $templateId 为url/{templateId}形式的templateId部分的数据
     */ 
	public function get_template($templateId){
		$user_id = $this->login_user_id;
		if (!$user_id) {
			printAjaxError('username', '会话已失效,请重新登录');
		}
		$data = $this->Sys_template_model->get2(array('template_id'=>$templateId));
		printAjaxData($data);
	}

    /**
     * 添加/更新对象
     * 根据请求参数是否携带对象id确定是更新还是添加
     */ 
	public function update_template(){
		$user_id = $this->login_user_id;
		if (!$user_id) {
			printAjaxError('username', '会话已失效,请重新登录');
		}
		$jsonData = getJsonData();
		$userInfo = $this->User_model->get("*",array('user_id'=>$user_id));		
		$operFields = get_oper_fields("template","post",OPERATE_TYPE_MODIFY,$userInfo ? $userInfo['user_name'] : "",'sys_template/update_template',$jsonData);			
		if($jsonData ){
            // 根据请求参数是否携带templateId确定是更新还是添加
			$templateId = NULL;
            if(isset($jsonData->templateId)){
                $templateId = $jsonData->templateId;
            }
            // 其它请求参数
            // ...
			printAjaxSuccess('',$templateId ? "修改成功" : "添加成功",$operFields,$this->Sys_oper_log_model);
		}else{
			printAjaxError("","无效的请求",$operFields,$this->Sys_oper_log_model);
		}
	}
	
    /**
     * 根据id逐个删除对象
     */ 
	private function delete_template_by_id($configId){
		$this->Sys_template_model->delete(array('template_id'=>$templateId));
	}
    /**
     * 删除对象
     * $templateIds为需要删除的对象数组,对应的请求为url/{templateIds},其中templateIds可为多个id的即可,比如"id1,id2,id3"
     */ 
	public function delete_template($templateIds){
		$user_id = $this->login_user_id;
		if (!$user_id) {
			printAjaxError('username', '会话已失效,请重新登录');
		}
		$userInfo = $this->User_model->get("*",array('user_id'=>$user_id));		
		$operFields = get_oper_fields("template","post",OPERATE_TYPE_MODIFY,$userInfo ? $userInfo['user_name'] : "",'sys_template/delete_template',$templateIds);		
		//执行删除操作
		printAjaxSuccess("","删除成功",$operFields,$this->Sys_oper_log_model );
	}	
}
添加若依接口映射表

在application/config/ruoyimapper.php中添加接口映射,比如

// 前端请求get类型的URL /system/template/list对应sys_template/get_template_list
$ruoyiApiMapper['get']['system']['template']['list'] = "sys_template/get_template_list";
// 前端请求get类型的URL /system/template/{templateId}对应sys_template/get_template
$ruoyiApiMapper['get']['system']['template']['index'] = "sys_template/get_template";
// 前端请求post类型的URL /system/template对应sys_template/update_template
$ruoyiApiMapper['post']['system']['template'] = "sys_template/update_template";
// 前端请求put类型的URL /system/template对应sys_template/update_template
$ruoyiApiMapper['put']['system']['template'] = "sys_template/update_template";
// 前端请求delete类型的URL /system/template对应sys_template/delete_template
$ruoyiApiMapper['delete']['system']['template'] = "sys_template/delete_template";

演示图

鸣谢

安全

该脚本利用mod_rewrite并阻止对 /public 文件夹之外的所有内容的访问。 您的.git文件夹/文件,操作系统临时文件,应用程序文件夹和其他所有内容都无法访问

证书

此项目的证书是基于 MIT. 您可以免费使用、修改或用于商用项目。

About

一个根据ruoyi-vue改造而来的超轻量级的PHP后台框架,php版本的、简化版的、若依前后端分离版的后台管理系统。

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published