错误信息:could not find driver (Connection: sqlite, SQL: PRAGMA foreign_keys = ON;)
原因是Laravel 11 默认使用 sqlite 作为数据库,而你的服务器上又没装php的sqlite扩展,所以报错。
解决办法,安装sqlite3扩展:
apt update
apt install php8.3-sqlite3
注意php版本号。
错误信息:could not find driver (Connection: sqlite, SQL: PRAGMA foreign_keys = ON;)
原因是Laravel 11 默认使用 sqlite 作为数据库,而你的服务器上又没装php的sqlite扩展,所以报错。
解决办法,安装sqlite3扩展:
apt update
apt install php8.3-sqlite3
注意php版本号。
<?php
// 获取文章第一张图片
function catch_that_image() {
global $post, $posts;
$first_img = '';
ob_start();
ob_end_clean();
$output = preg_match_all('/<img.+?src=[\'"]([^\'"]+)[\'"].*?>/i', $post->post_content, $matches);
$first_img = $matches[1][0];
if (empty($first_img)) {
$first_img = "/path/to/default.png";
}
return $first_img;
}
改进版,增加了默认图片的显示,以及文章中没有图片时的判断:
<?php
// 获取文章第一张图片
function catch_that_image() {
global $post, $posts;
$first_img = '';
ob_start();
ob_end_clean();
$output = preg_match_all('/<img.+?src=[\'"]([^\'"]+)[\'"].*?>/i', $post->post_content, $matches);
if ($output) {
$first_img = $matches[1][0];
}
if (empty($first_img)) {
$first_img = bloginfo('template_url') . "/assets/images/default_image.jpeg";
}
return $first_img;
}
默认图片:default_image.jpeg,需要自己找一张。
一个分页问题搞了一晚上和一上午,分页函数`paginate_links`生成的链接一直是`/page/2`这种,并且打不开,提示找不到页面。
google+baidu 几乎找遍了也没找到解决方案。最后在看`paginate_links`参数时,发现第一个参数`base`的意思是”Base of the paginated url”,翻译过来就是“分页URL的基础”,忽然意识到是不是这个参数的原因。
由于之前分页代码是在网上随便找的,`base`参数是
$big = 999999999;
'base' => str_replace( $big, '%#%', esc_url( get_pagenum_link( $big ) ) ),
打印了一下它的值是https://notes.wujie.me/case/page/%#%,也就是说生成的分页链接就是/case/page/%#%这种格式的。
那么到此就可以确定是该参数的问题,解决办法就是不使用该参数,或者使用它的默认值%_%,即可把分页URL改成https://notes.wujie.me/case?page=2这种默认样式。
至于为什么只有默认URL样式才能访问,而page/2这样样式会找不到页面,就不得而知了。
最终改过之后的代码如下:
global $wp_query;
echo paginate_links( array(
'base' => '%_%',
'format' => '?page=%#%',
'current' => max( 1, get_query_var('page') ),
'total' => $wp_query->max_num_pages
) );
附一个兼容boostrap4的分页样式:
// 兼容bootstrap4的分页
function bootstrap_pagination(\WP_Query $wp_query = null, $echo = true) {
if (null === $wp_query) {
global $wp_query;
}
$pages = paginate_links(
[
//'base' => str_replace( 999999999, '%#%', esc_url( get_pagenum_link( 999999999 ) ) ),
'format' => '?page=%#%',
'current' => max(1, get_query_var('paged')),
'total' => $wp_query->max_num_pages,
'type' => 'array',
'show_all' => false,
'end_size' => 3,
'mid_size' => 1,
'prev_next' => true,
'prev_text' => __('« 上一页'),
'next_text' => __('下一页 »'),
'add_args' => false,
'add_fragment' => ''
]
);
if (is_array($pages)) {
//$paged = ( get_query_var( 'paged' ) == 0 ) ? 1 : get_query_var( 'paged' );
$pagination = '<div class="pagination"><ul class="pagination">';
foreach ($pages as $page) {
$pagination .= '<li class="page-item' . (strpos($page, 'current') !== false ? ' active' : '') . '"> ' . str_replace('page-numbers', 'page-link', $page) . '</li>';
}
$pagination .= '</ul></div>';
if ($echo) {
echo $pagination;
} else {
return $pagination;
}
}
return null;
}
经验教训:复制网上的代码时,要弄懂每一行在干什么,不要随意粘贴到自己的项目中。
注册自定义文章类型,代码如下:
add_action('init', 'my_custom_post_product');
function my_custom_post_product() {
$labels = array(
'name' => _x('产品中心', 'post type 名称'),
'singular_name' => _x('产品', 'post type 单个 item 时的名称,因为英文有复数'),
'add_new' => _x('添加产品', '添加新内容的链接名称'),
'add_new_item' => __('添加新产品'),
'edit_item' => __('编辑产品'),
'new_item' => __('新产品'),
'all_items' => __('产品列表'),
'view_item' => __('查看产品'),
'search_items' => __('搜索产品'),
'not_found' => __('没有找到有关产品'),
'not_found_in_trash' => __('回收站里面没有相关产品'),
'parent_item_colon' => '',
'menu_name' => '产品管理'
);
$args = array(
'labels' => $labels,
'description' => '我们网站的产品信息',
'public' => true,
'menu_position' => 5,
'menu_icon' => 'dashicons-money-alt',
// 支持的功能,还可以添加:'excerpt', , 'comments'
'supports' => array('title', 'editor', 'thumbnail'),
/*这个设置为true,
才能在前台 single-[post_type].php 和 archive-[post_type].php 显示列表*/
'has_archive' => true
);
// 注册文章类型,第一个参数为类型名称,即post type name
register_post_type('product', $args);
}
为新注册的类型,添加分类功能,代码如下:
/**
* 为产品 post type 添加分类功能
*/
add_action('init', 'my_taxonomies_product', 0);
function my_taxonomies_product() {
$labels = array(
'name' => _x('产品分类', 'taxonomy 名称'),
'singular_name' => _x('产品分类', 'taxonomy 单数名称'),
'search_items' => __('搜索产品分类'),
'all_items' => __('所有产品分类'),
'parent_item' => __('该产品分类的上级分类'),
'parent_item_colon' => __('该产品分类的上级分类:'),
'edit_item' => __('编辑产品分类'),
'update_item' => __('更新产品分类'),
'add_new_item' => __('添加新的产品分类'),
'new_item_name' => __('新产品分类'),
'menu_name' => __('产品分类'),
);
$args = array(
'labels' => $labels,
'hierarchical' => true,
);
/** 注册分类,第一个参数为分类法的名字,即taxonomy
第二个参数为该分类属于哪个文章类型 */
register_taxonomy('product_category', 'product', $args);
}
为新注册的文章类型添加额外的输入框,即 meta box
/**
* 为产品发布类型 添加自定义 Meta Box
* 功能特征 meta box
*/
add_action('add_meta_boxes', 'product_gongneng');
function product_gongneng() {
// add_meta_box( $id, $title, $callback, $post_type, $context,$priority, $callback_args );
add_meta_box(
'product_gongneng', // id
'功能特征', // title
'product_gongneng_meta_box', // callback
'product', // post_type
'normal', // context
'low' // priority
);
}
/**
* 为meta box 添加html表单
*/
function product_gongneng_meta_box($post) {
// 创建临时隐藏表单,为了安全
wp_nonce_field('product_gongneng_meta_box', 'product_gongneng_meta_box_nonce');
// 获取之前存储的值
$field_value = get_post_meta($post->ID, '_product_gongneng', false);
?>
<p>
<label for="_product_gongneng"></label>
<?php
$settings = array(
'quicktags' => array('buttons' => 'em,strong,link',),
'quicktags' => true,
'tinymce' => true,
'editor_height' => 100, // In pixels, takes precedence and has no default value
'textarea_rows' => 20, // Has no visible effect if editor_height is set, default is 20
);
wp_editor(html_entity_decode($field_value[0]), '_product_gongneng', $settings);
?>
</p>
<?php
}
// 保存meta_box
add_action('save_post', 'product_gongneng_save_meta_box');
function product_gongneng_save_meta_box($post_id) {
// 安全检查
// 检查是否发送了一次性隐藏表单内容(判断是否为第三者模拟提交)
if (!isset($_POST['product_gongneng_meta_box_nonce'])) {
echo 'a11111';
exit();
return;
}
// 判断隐藏表单的值与之前是否相同
if (!wp_verify_nonce($_POST['product_gongneng_meta_box_nonce'], 'product_gongneng_meta_box')) {
echo '222';
exit();
return;
}
// 判断该用户是否有权限
if (!current_user_can('edit_post', $post_id)) {
echo '333';
exit();
return;
}
// 判断 Meta Box 是否为空
if (!isset($_POST['_product_gongneng'])) {
echo '444';
exit();
return;
}
// 使用 wpautop 函数,是因为表单中 使用了富文本编辑器,要对文本进行处理
$gongeng = htmlentities(wpautop($_POST['_product_gongneng']));
$_product_gongneng = sanitize_text_field($gongeng);
// 把字段值保存到数据库
update_post_meta($post_id, '_product_gongneng', $_product_gongneng);
}
查看所有启用的服务:
systemctl list-unit-files --type=service
该命令会列出所有服务的启动状态,其中标记为 enabled 的服务会在开机时自动启动。
查看当前正在运行的服务:
systemctl list-units --type=service
这个命令会列出当前正在运行的服务,已启动的服务会标记为 running。
systemctl list-unit-files --type=service 输出 列表太长,如果不想看整个列表,只想简单地查看启用的服务,可以运行以下命令:
systemctl list-unit-files --type=service | grep enabled
这个命令会列出所有启用(enabled)的服务,只有那些会在系统启动时自动启动的服务会被显示。
查看当前运行的服务
systemctl list-units --type=service --state=running
这个命令会显示当前正在运行的服务,但它不会直接列出所有已配置为开机启动的服务。它只会列出系统启动后当前处于运行状态的服务。
检查特定服务是否设置为开机启动
systemctl is-enabled <service-name>
例如,要查看 ssh 服务是否在开机时启动:
systemctl is-enabled ssh
如果返回 enabled,则表示该服务已配置为开机启动。
使用 grep 筛选开机启动的服务(更简洁的命令)
systemctl list-unit-files --type=service | awk '$2=="enabled" {print $1}'
这个命令会只输出那些标记为 enabled 的服务名称,避免显示其他无关的服务信息。
最后,也可以查看/etc/init.d/目录(SysVinit 脚本,这个适合于老旧的系统,新系统中也会有这个目录,但不太推荐使用了)
ls /etc/init.d/
查看已安装的内核列表:
dpkg --list | grep linux-image
查看当前使用中的内核版本:
uname -r
如果有新内核,需要重启系统,重新启动后,会自动使用最新版本的内核。
最好不要折腾内核,稳定性第一!
查看kexec是否安装 :
dpkg -l | grep kexec-tools
安装 :
apt install kexec-tools
正常来说不需要这个东西,感觉没什么用,都要重启了,也不差那几秒。所以说,更新的时候如果有新内核,提示是否使用kexec,那么选No就行了,正常重启即可。
如果你使用laravel installer来安装框架,那么当需要更新laravel installer时可以执行以下命令:
composer global remove laravel/installer
composer global require laravel/installer
你大概看出来了,对!就是卸载然后重装,就是这么简单又暴力,喜欢吗?
该标题的意思即:Laravel 中的多重身份验证,简化了一下标题,让人能看懂。
在 Laravel 中,“多重身份验证”(也称为“多重保护身份验证”)是指在单个应用程序中管理多个用户身份验证系统的能力。当您有不同类型的用户(例如普通用户和管理员)且每个用户都有自己的身份验证要求和用户模型时,这非常有用。
要在 Laravel 中实现多重身份验证,您通常需要遵循以下步骤:
第 1 步:创建多个用户模型:
为要验证的每种类型的用户创建单独的用户模型。例如,您可能有一个User针对普通用户的模型和一个Admin针对管理员的模型。您可以使用以下artisan命令生成这些模型:
php artisan make:model User
php artisan make:model Admin
注意:这一步可以省略,完全可以都用User表。
步骤 2:配置身份验证防护:
在config/auth.php文件中,定义多个防护(guard),每个防护与一个用户模型关联。Laravel 允许您为每个守卫配置不同的身份验证驱动程序。例如,您可以将“web”防护用于具有基于会话的身份验证的普通用户,将“admin”防护用于具有基于会话或基于令牌的身份验证的管理员。
下面是一个简化的文件示例config/auth.php:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
],
第 3 步:定义身份验证提供程序:
为每个用户模型配置身份验证提供程序。提供者决定 Laravel 应在何处检索用户记录。在同一config/auth.php文件中,为指定相应 Eloquent 模型的“users”和“admins”定义提供程序:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Models\Admin::class,
],
],
第 4 步:实施身份验证逻辑:
在你的应用程序中,根据所选的防护实现身份验证逻辑。你可以使用auth()辅助方法来访问所需的防护:
// Authenticate a regular user
if (auth()->guard('web')->attempt(['email' => $email, 'password' => $password])) {
// User is logged in
}
// Authenticate an administrator
if (auth()->guard('admin')->attempt(['email' => $email, 'password' => $password])) {
// Admin is logged in
}
第 5 步:保护路由:
使用中间件根据所选的防护来保护路由。例如,您可以应用“auth:web”中间件来保护普通用户的路由,使用“auth:admin”中间件来保护管理员的路由:
Route::middleware(['auth:web'])->group(function () {
// Routes accessible to regular users
});
Route::middleware(['auth:admin'])->group(function () {
// Routes accessible to administrators
});
第 6 步:注销:
要注销用户,可以logout在相应的守卫上使用该方法:
auth()->guard('web')->logout(); // Log out a regular user
auth()->guard('admin')->logout(); // Log out an administrator
结论:
这就是 Laravel 中实现多重身份验证的基本流程。你可以创建多个用户模型(或者只用User模型),配置防护和提供程序,实施身份验证逻辑,并根据所选防护保护路由。这允许你在单个 Laravel 应用程序中使用自己的身份验证系统来管理不同类型的用户。
参考文章:
把以下代码放在 views/vendor/pagination/layui.blade.php里,这个路径是使用 php artisan vendor:publish --tag=laravel-pagination 发布出来的:
<div class="layui-box layui-laypage layui-laypage-default">
{{-- Previous Page Link --}}
@if ($paginator->onFirstPage())
<a class="layui-laypage-prev layui-disabled">上一页</a>
@else
<a class="layui-laypage-prev" href="{{ $paginator->previousPageUrl() }}">上一页</a>
@endif
{{-- Pagination Elements --}}
@foreach ($elements as $element)
{{-- Array Of Links --}}
@if (is_array($element))
@foreach ($element as $page => $url)
@if ($page == $paginator->currentPage())
<span class="layui-laypage-curr"><em class="layui-laypage-em"></em><em>{{ $page }}</em></span>
@else
<a href="{{ $url }}">{{ $page }}</a>
@endif
@endforeach @endif @endforeach
{{-- Next Page Link --}}
@if ($paginator->hasMorePages())
<a class="layui-laypage-next" href="{{ $paginator->nextPageUrl() }}">下一页</a>
@else
<a class="layui-laypage-next layui-disabled" href="{{ $paginator->nextPageUrl() }}">下一页</a>
@endif
</div>
使用:
<div style="text-align: center">
{{ $rooms->links('vendor.pagination.layui') }}
</div>
补充一个Layui2.9.x的样式:
<div class="layui-box layui-laypage layui-laypage-default">
{{-- Previous Page Link --}}
@if ($paginator->onFirstPage())
<a class="layui-laypage-prev layui-disabled">上一页</a>
@else
<a class="layui-laypage-prev" href="{{ $paginator->previousPageUrl() }}">上一页</a>
@endif
{{-- Pagination Elements --}}
@foreach ($elements as $element)
{{-- Array Of Links --}}
@if (is_array($element))
@foreach ($element as $page => $url)
@if ($page == $paginator->currentPage())
<span class="layui-laypage-curr"><em class="layui-laypage-em"></em><em>{{ $page }}</em></span>
@else
<a href="{{ $url }}">{{ $page }}</a>
@endif
@endforeach @endif @endforeach
{{-- Next Page Link --}}
@if ($paginator->hasMorePages())
<a class="layui-laypage-next" href="{{ $paginator->nextPageUrl() }}">下一页</a>
@else
<a class="layui-laypage-next layui-disabled" href="{{ $paginator->nextPageUrl() }}">下一页</a>
@endif
</div>
有时,需要对分页代码进行自定义,那么此时就需要把分页视图发布出来:
php artisan vendor:publish --tag=laravel-pagination