reecem/static-form

v0.2.1 2022-08-08 21:06 UTC

This package is auto-updated.

Last update: 2024-09-22 19:54:16 UTC


README

Latest Version on Packagist PHPUnit Tests Total Downloads Styling

从 Next.JS 和 Netlify 或任何其他静态网站服务器内部处理您的 Laravel 应用中的静态表单提交。

安装

您可以通过 composer 安装此包

composer require reecem/static-form

要安装应用程序,您可以执行以下操作

php artisan static-form:install --provider --config

这将安装配置文件和服务提供者,但您可以单独选择每个文件,或者使用以下命令

您可以使用以下命令发布配置文件

php artisan vendor:publish --provider="ReeceM\StaticForm\StaticFormServiceProvider" --tag="static-form-config"

您可以使用以下命令发布服务提供者文件

php artisan vendor:publish --provider="ReeceM\StaticForm\StaticFormServiceProvider" --tag="static-form-provider"

您需要将以下内容添加到 config/app.php 文件中

        /*
         * Package Service Providers...
         */
+        App\Providers\StaticFormServiceProvider::class

您可以在此处查看文档 https://static-form.pkgpg.dev

使用方法

总体来说,当前版本的用法是您可以使用包中间件在您定义的控制器上,这将使用您的控制器来处理请求数据。

创建令牌

第一步是生成您的令牌,为此您可以使用控制台命令

php artisan static-form --refresh

这将生成您的令牌,它将在该会话期间仅显示纯文本版本。

另一种方法是调用 API 端点来生成新的令牌。API 通过 App\Providers\StaticFormServiceProvider::class 中定义的 Gate 进行安全保护

您可以在其中定义任何逻辑,允许仅授权人员访问应用程序。

要调用 API 端点,目前您可以通过自定义 UI 和 JavaScript 代码向端点发出请求。

URL 部分的 static-form 可以更改,它来自配置键 static-form.path

创建令牌的响应将是以下 JSON 格式,状态为 201

{
    "plain_token": "random_string_that_is_40_characters_long",
    "message": "Token Created, please keep this as it is available once"
}
  • 制作插件 UI,决定它是包含在包中还是作为单独的片段。

使用中间件

要使用中间件,您可以使用配置文件定义一个路由,我建议您使用 API 端点,因为它无状态,并且不需要 CSRF 令牌。

// routes/api.php

Route::group([
    'middleware' => config('static-form.middleware.forms'),
], function () {
    // A controller that you have created.
    Route::post('/contact', StaticContactController::class)->name('contact.create');
});

提交表单

在您的静态网站上,您可以拥有您的联系表单。处理表单的方式是通过主机提供商的 API 部分。

因此,对于 Vercel 应用程序,您可以在 api 目录下创建一个新文件。

对于代码的 API 部分

// api/contactus.js

/**
 * Create a contact request to the main server.
 *
 * @param {http.IncomingMessage} req
 * @param {*} res
 */
import { APP_TOKEN, APP_URL } from "../../../lib/constants"

export default async function contactus(req, res) {

  if (req.method !== 'POST') {
    return res.status(400);
  }

  if (req.body?.website) {
    return res.status(200);
  }

  let body = JSON.parse(req.body)
  let {_token, xsrf} = body.token;
  delete body.token

  const request = await fetch(
    `${APP_URL}/api/static-form/contactus`,
    {
      method: 'POST',
      body: JSON.stringify(body),
      headers: {
        'X-STATIC-FORM': APP_TOKEN,
        'Content-Type': 'application/json',
        'Accept': 'application/json',
        "x-requested-with": "XMLHttpRequest",
      },
    }
  )

  if (request.status !== 201 ) {
    let json = await request.json()

    throw new Error(json.message || 'Failed to fetch API');
  }

  const json = await request.json()

  if (json.errors) {
    console.error(json.errors)
    throw new Error('Failed to fetch API, json errors')
  }

  return res.status(201).json(json.data ?? {});
}

您可以为前端尝试一个简单的表单布局

import React, { useCallback, useEffect, useRef, useState } from 'react'

const ContactUs = () => {
    const [contactName, setContactName] = useState('')
    const [contactEmail, setContactEmail] = useState('')
    const [honey, setHoney] = useState('')

    function handleForm(e) {
        e.preventDefault()

        if (honey.length >= 1) {
            return
        }

        let body = {
            name: contactName,
            email: contactEmail,
        }

        fetch(
            `${location.origin}/api/contactus`,
            {
                method: 'POST',
                body: JSON.stringify(body)
            }
        )
        .then(response => {
            console.debug(response);
        })
        .catch(error => {
            console.error(error)
        })
    }

    return (
        <>
            <form onSubmit={handleForm}>
                <div style={{marginBottom: '0.75rem'}}>
                    <label htmlFor="name">Name</label>
                    <input 
                        name="name" 
                        id="name"
                        value={contactName}
                        onChange={e => setContactName(e.target.value)}
                        placeholder="Your Name"
                        type="text"
                    />
                </div>
                <div style={{marginBottom: '0.75rem'}}>
                    <label htmlFor="email">Email</label>
                    <input 
                        name="email" 
                        id="email"
                        value={contactEmail}
                        onChange={e => setContactEmail(e.target.value)}
                        placeholder="Your email"
                        type="email"
                    />
                </div>
                <input style={{display: 'none'}} name="website" value={honey} onChange={e => setHoney(e.target.value)}> <!-- The honeypot field -->
                <button type="submit">Submit</button>
            </form>
        </>
    )
}

export default ContactUs;

测试

测试目前正在进行中,有一些 :),我正在手动在实际应用程序中测试以确保它正常工作。

composer test

变更日志

有关最近更改的更多信息,请参阅 CHANGELOG

贡献

有关详细信息,请参阅 CONTRIBUTING

安全漏洞

有关报告安全漏洞的详细信息,请参阅 我们的安全策略

鸣谢

许可证

MIT许可(MIT)。请参阅许可文件获取更多信息。