定制 eboreum/phpstan-types 二次开发

按需修改功能、优化性能、对接业务系统,提供一站式技术支持

邮箱:yvsm@zunyunkeji.com | QQ:316430983 | 微信:yvsm316

eboreum/phpstan-types

Composer 安装命令:

composer require --dev eboreum/phpstan-types

包简介

Custom PHPStan (https://phpstan.org/) types, e.g. `uuid-string`, `datetime-string`, and `email-string`.

README 文档

README

license pipeline status coverage report PHPStan Level

eboreum-phpstan-types-logo

Custom PHPStan (https://phpstan.org/) types, e.g. uuid-string, datetime-string, and email-string.

Requirements

"php": "^8.5",
"ext-iconv": "*",
"ext-intl": "*",
"beberlei/assert": "^3.3",
"composer/semver": "^3.4",
"egulias/email-validator": "^4.0",
"globalcitizen/php-iban": "^4.2",
"league/iso3166": "^4.4",
"league/uri": "^7.8",
"phpstan/phpstan": "^2.1",
"ramsey/uuid": "^4.9",
"respect/validation": "^2.2",
"sabberworm/php-css-parser": "^9.3",
"seld/jsonlint": "^1.11",
"symfony/intl": "^8.0",
"symfony/uid": "^8.0"

For more information, see the composer.json file.

Installation

Via Composer (https://packagist.org/packages/eboreum/phpstan-types):

composer require --dev eboreum/phpstan-types

Via GitLab:

git clone git@gitlab.com:eboreum/phpstan-types.git

Load it into PHPStan

Include the extension in your phpstan.neon (or phpstan.neon.dist):

includes:
    - vendor/eboreum/phpstan-types/extension.neon

Usage

Use the type names as PHPDoc type annotations in your PHP code:

/** @param uuid-string $id */
function findUser(string $id): void { ... }

/** @return datetime-string */
function getTimestamp(): string { ... }

/** @var email-string $address */
$address = 'user@example.com';

Generic types accept parameters directly in the annotation:

/** @param float-between<0,1> $ratio */
function scale(float $ratio): void { ... }

/** @param multiple-of-int<8> $alignment */
function alignTo(int $alignment): void { ... }

/** @param fixed-string<36> $uuid */
function parseUuid(string $uuid): void { ... }

Overview

DefinitionDescriptionExamplesCategories
absolute-uri-stringAbsolute RFC 3986 URI with a required scheme. Host name is optional. If host name is required, please use absolute-uri-with-host-string instead.mailto:test@example.com, https://example.com, ftp://ftp.example.com/file.txt🔗 URI
absolute-uri-with-host-stringAbsolute RFC 3986 URI with a required scheme and required host name.https://example.com, ftp://ftp.example.com/file.txt, http://localhost:8080/test🔗 URI
alphanumeric-stringString containing only ASCII letters and digits. Optional length parameter supported.abc123, A1B2C3, hello42🔤 Simple string format
ascii-lowercase-stringNon-empty 7-bit ASCII string where all ASCII letters are lowercase; digits, symbols, and ASCII control characters are allowed.hello, abc123, foo-bar, foo_bar🔤 Simple string format
ascii-stringString containing only 7-bit ASCII characters.hello, ABC123, foo-bar, test@example.com🔤 Simple string format
ascii-uppercase-stringNon-empty 7-bit ASCII string where all ASCII letters are uppercase; digits, symbols, and ASCII control characters are allowed.HELLO, ABC123, FOO-BAR, FOO_BAR🔤 Simple string format
base64-stringString containing syntactically valid standard Base64 data. Define separately whether URL-safe Base64 and missing padding are accepted.SGVsbG8=, YWJjMTIz, TWFu🔀 Encoding
base64url-stringString containing syntactically valid Base64URL data using - and _ instead of + and /. Padding may optionally be omitted.SGVsbG8, SGVsbG8=, eyJhbGciOiJIUzI1NiJ9, YWJjMTIz🔗 URI
🔀 Encoding
bic-stringValid ISO 9362 Business Identifier Code.DEUTDEFF, NEDSZAJJ, DABADKKKXXX🆔 Identification
🤝 Business
byte-length-between<M,N>String whose byte length (strlen) is between M and N inclusive, where 0 <= M <= N.byte-length-between<1,255>, byte-length-between<8,8>, byte-length-between<0,100>🔤 Simple string format
camel-case-stringLower camelCase identifier beginning with a lowercase ASCII letter.fooBar, myVariable1, apiClient🔤 Simple string format
composer-version-stringValid Composer version constraint string.^1.2, ~2.0, >=1.0 <2.0, dev-main🔤 Simple string format
country-calling-code-stringInternational country calling code as a numeric string without leading + or 00.1, 44, 45, 49☎️ Telephony
css-color-stringCSS color string accepted by one of the supported color-specific types: hex, RGB/RGBA, HSL/HSLA, HWB, or named color.#ff00aa, rgb(1, 2, 3), hsl(120 50% 50%), hwb(90 10% 20%), purple🎨 Appearance (GUI)
css-hex-color-stringCSS hexadecimal color literal.#fff, #ff00aa, #1234, #11223344🎨 Appearance (GUI)
css-hsl-color-stringCSS HSL color function in normalized form (no leading/trailing/repeated spaces inside parentheses, and no semicolons). Concrete grammar validation is delegated to sabberworm/php-css-parser.hsl(0 100% 50%), hsla(120, 50%, 50%, 0.5), hsl(220 90% 55% / 0.5)🎨 Appearance (GUI)
css-hwb-color-stringCSS HWB color function in normalized form (no leading/trailing/repeated spaces inside parentheses, and no semicolons). Concrete grammar validation is delegated to sabberworm/php-css-parser.hwb(0 0% 0%), hwb(220 10% 10% / 0.5), hwb(220 10% 85%)🎨 Appearance (GUI)
css-named-color-stringCSS named color keyword. Should be validated against the CSS named color list rather than by regex alone.red, purple, rebeccapurple, transparent, currentcolor🎨 Appearance (GUI)
css-rgb-color-stringCSS RGB color function in normalized form (no leading/trailing/repeated spaces inside parentheses, and no semicolons). Allows legacy comma syntax and modern space/slash syntax.rgb(1, 2, 3), rgb(1, 2, 3, 0.5), rgba(1, 2, 3, 0.5), rgb(1 2 3 / 50%)🎨 Appearance (GUI)
date-stringISO 8601 calendar date string with month constrained to 01-12 and day constrained to 01-31, then validated as a real Gregorian calendar date to reject magic/relative date strings.2025-01-31, 1999-12-24, 2024-02-29📅 Date
datetime-iso8601-local-stringStrict ISO-like local date-time string without timezone offset, using T as separator, with month/day/hour/minute/second constrained to valid numeric ranges before full calendar validation.2025-01-31T13:45:00, 2024-12-24T08:00:00📅 Date 🕒 Time
datetime-iso8601-stringStrict ISO-like date-time string using T as separator and timezone as either P offset or UTC Z.2025-01-31T13:45:00+00:00, 2024-12-24T08:00:00+01:00, 2025-01-31T13:45:00Z📅 Date 🕒 Time
datetime-local-stringFlexible local date-time string without timezone offset, allowing either T or space between date and time, with month/day/hour/minute/second constrained to valid numeric ranges before full calendar validation.2025-01-31T13:45:00, 2025-01-31 13:45:00📅 Date 🕒 Time
datetime-stringFlexible date-time string with timezone, allowing either T or space separator, and timezone as P, O, or UTC Z.2025-01-31T13:45:00+00:00, 2025-01-31 13:45:00+0000, 2025-01-31T13:45:00Z📅 Date 🕒 Time
decimal-stringCanonical decimal number string using . as decimal separator and without exponent notation.0, 12.34, -99.5, 1000🔢 Numbers
digit-stringNon-empty ASCII digit sequence.1, 42, 000123🔢 Numbers
duration-iso8601-stringISO 8601 duration string.P1D, PT30M, P2Y6M5DT12H35M30S📅 Date 🕒 Time
e164-stringE.164 formatted phone number: + followed by up to 15 digits, no spaces or separators.+4512345678, +14155552671, +4412345678☎️ Telephony
ean-stringValid EAN-8 or EAN-13 barcode string with correct check digit.73513537, 4006381333931, 5901234123457🆔 Identification
eid-stringeUICC Identifier for embedded SIM (eSIM) hardware; globally unique 32-digit numeric string identifying the eSIM chip.89049032426600000000000000001234, 89033024000000000000000000010001☎️ Telephony
email-stringSyntactically valid email address. Specify whether DNS/MX checks and internationalized addresses are included.user@example.com, john.doe+test@gmail.com, a@b.dk📧 Email
even-intInteger divisible by 2.0, 2, -4, 42🔢 Numbers
file-extension-stringFile extension without leading dot, path separators, NUL, or whitespace; dot-separated multi-part extensions are allowed.txt, pdf, docx, tar, tar.gz
file-name-stringPortable filename segment valid across Windows, macOS, and Linux, excluding dot-only segments (. and ..).document.txt, invoice-2025.pdf, my_photo.png📄 File system
fixed-byte-string<N>String whose byte length is exactly N; uses byte length, not character count.abcd, 12345678🔤 Simple string format
fixed-string<N>String whose character length is exactly N; multibyte-safe.abcd, æøå1🔤 Simple string format
float-between<MIN,MAX>Float constrained to the inclusive range from MIN to MAX, where both bounds are decimal literals and MIN <= MAX.float-between<0,1>, float-between<-1.5,2.5>, float-between<10,10>🔢 Numbers
hex-lowercase-stringNon-empty lowercase hexadecimal string. Optional length parameter supported.deadbeef, ff00aa, 123abc🔤 Simple string format
hex-stringNon-empty hexadecimal string. Optional length parameter supported.deadBEEF, ff00aa, ABC123🔤 Simple string format
🧩 Content type
hex-uppercase-stringNon-empty uppercase hexadecimal string. Optional length parameter supported.DEADBEEF, FF00AA, ABC123🔤 Simple string format
hostname-stringValid DNS hostname without scheme, port, path, query, or fragment. Define IDN/punycode behavior.example.com, localhost, api.internal🔗 URI
http-header-nameValid HTTP header field-name token (RFC 7230 token syntax).Content-Type, X-Request-ID, ETag🌐 Web/HTTP
http-header-valueValid HTTP header field-value without CR/LF control characters.application/json, Bearer abc.def.ghi, text/plain; charset=utf-8🌐 Web/HTTP
http-method-stringValid uppercase HTTP request method token.GET, POST, PATCH, DELETE🔗 URI
🌐 Web/HTTP
http-url-stringAbsolute web URL with scheme http or https and a required host.http://example.com, https://example.com, http://localhost:8080/test🔗 URI
🌐 Web/HTTP
iban-stringValid International Bank Account Number. Prefer validating both structure and checksum.DK5000400440116243, GB82WEST12345698765432🆔 Identification
💰 Money
iccid-stringSIM card Integrated Circuit Card Identifier; typically 19–20 digits, may include a trailing Luhn check digit.8945026102100024374F, 89314404000025113290☎️ Telephony
idd-prefixed-phone-number-stringInternational phone number written with the IDD exit prefix 00 instead of +.004512345678, 00447911123456, 001415555...☎️ Telephony
imei-stringInternational Mobile Equipment Identity; 15-digit numeric string identifying mobile equipment, with a Luhn check digit.356938035643809, 490154203237518☎️ Telephony
imeisv-stringInternational Mobile Equipment Identity and Software Version; 16-digit variant of IMEI including a 2-digit software version.3569380356438090, 4901542032375180☎️ Telephony
imsi-stringInternational Mobile Subscriber Identity; 14–15-digit numeric string identifying a subscriber on a mobile network, composed of MCC + MNC + MSIN.238010123456789, 310260000000000☎️ Telephony
int-as-stringCanonical integer string: 0, positive integers without leading zeroes, or negative integers. Cannot be expected to be reliably converted to int because the value may exceed PHP_INT_MIN or PHP_INT_MAX. Does not accept scientific notation.0, 42, -99, 123456🔢 Numbers
international-phone-number-stringInternationally formatted phone number including country calling code, in any recognized notation (e.g. E.164, IDD-prefixed, or human-readable with separators).+4512345678, 004512345678, +1 415 555 2671☎️ Telephony
ip-stringValid IPv4 or IPv6 address string.127.0.0.1, ::1, 2001:db8::1🖧 Network
ipv4-cidr-stringIPv4 CIDR block with required prefix length.192.168.0.0/24, 10.0.0.1/32🖧 Network
ipv4-stringValid IPv4 address in dotted-decimal notation. Prefer rejecting octal, hex, shorthand, and leading-zero forms.127.0.0.1, 192.168.1.1, 8.8.8.8🖧 Network
ipv6-cidr-stringIPv6 CIDR block with required prefix length.2001:db8::/32, ::1/128, fe80::/64🖧 Network
ipv6-stringValid IPv6 address, including compressed forms. Define whether IPv4-mapped IPv6 is accepted.::1, 2001:db8::1, fe80::1🖧 Network
isbn-stringValid ISBN-10 or ISBN-13 string (hyphens/spaces allowed) with correct checksum.0306406152, 0-306-40615-2, 978-0-306-40615-7🆔 Identification
iso-3166-1-alpha-2-stringISO 3166-1 alpha-2 country code.DK, US, DE🌍 Country
iso-3166-1-alpha-3-stringISO 3166-1 alpha-3 country code.DNK, USA, DEU🌍 Country
iso-3166-1-numeric-stringISO 3166-1 numeric country code as exactly three digits.208, 840, 276🌍 Country
iso-639-1-stringISO 639-1 language code.en, da, fr💬 Language
iso-639-2-stringISO 639-2 language code.eng, dan, fra💬 Language
iso-639-3-stringISO 639-3 language code.eng, dan, fra💬 Language
iso-639-6-stringISO 639-6 language code.engl, dani💬 Language
iso4217-currency-code-stringISO 4217 currency code.USD, EUR, DKK, JPY💰 Money
json-stringString that decodes as valid JSON. Define whether duplicate keys, top-level scalars, and invalid UTF-8 are accepted.{"foo":"bar"}, [1,2,3], true, "hello"🔣 Programming
jwt-stringJSON Web Token in compact serialization form. This should validate syntax only unless signature verification is explicitly included.eyJhbGciOi...eyJzdWIiOi...SflKxwRJS...🔐 Authentication
🔀 Encoding
kebab-case-stringLowercase kebab-case identifier using hyphens as separators.hello-world, api-client, my-variable-1🔤 Simple string format
locale-stringLocale identifier matching the configured locale regex.en, en_US, da-DK🌍 Country
💬 Language
✍️ Writing
mac-address-stringValid MAC address string. Define accepted notation variants.00:1A:2B:3C:4D:5E, AA-BB-CC-DD-EE-FF🆔 Identification
🖧 Network
mb-lowercase-stringA UTF-8 string, which may contain any digits, symbols, ASCII control characters, but all letters must be lowercase according to mb_strtolower(..., 'UTF-8').hello, foo_bar, øæå, héllo🔤 Simple string format
mb-uppercase-stringA UTF-8 string, which may contain any digits, symbols, ASCII control characters, but all letters must be uppercase according to mb_strtoupper(..., 'UTF-8').HELLO, FOO_BAR, ØÆÅ, HÉLLO🔤 Simple string format
mcc-stringMobile Country Code; a 3-digit numeric string identifying the country of a mobile network operator.238, 310, 262☎️ Telephony
mccmnc-stringCombined Mobile Country Code and Mobile Network Code identifying a unique PLMN/operator; typically 5 or 6 digits.23801, 310260, 26201☎️ Telephony
md5-stringExactly 32 lowercase hexadecimal characters.d41d8cd98f00b204e9800998ecf8427e🔀 Encoding
meid-stringMobile Equipment Identifier used in CDMA networks; 14 hexadecimal digits or 18 decimal digits.A0000000049E68, 354403064522046☎️ Telephony
mime-type-stringMIME media type with valid type/subtype tokens. Define whether parameters are allowed.text/plain, application/json, image/png📄 File system
🧩 Content type
mnc-stringMobile Network Code; a 2- or 3-digit numeric string identifying the operator within a country (used together with MCC).01, 26, 001☎️ Telephony
msin-stringMobile Subscription Identification Number; the subscriber-specific suffix of an IMSI, represented here as 9 or 10 digits.012345678, 1234567890☎️ Telephony
msisdn-stringMobile Station International Subscriber Directory Number; the full E.164 number used to route calls and SMS to a subscriber, without the leading +.4512345678, 14155552671☎️ Telephony
msrn-stringMobile Station Roaming Number; a temporary MSISDN-like number assigned by a visited network to route calls to a roaming subscriber.4599887766, 14087654321☎️ Telephony
multiple-of-int<N>Integer divisible by non-zero integer N.multiple-of-int<2>, multiple-of-int<3>, multiple-of-int<-5>🔢 Numbers
national-significant-number-stringNational Significant Number; the subscriber number portion of a phone number excluding the country calling code.512345678, 7911123456, 30123456☎️ Telephony
negative-floatFloat strictly less than 0.0. Decide whether negative zero (-0.0) is included or rejected.-1.5, -0.1, -42.0🔢 Numbers
negative-int-as-stringCanonical negative integer string. Cannot be expected to be reliably converted to int because the value may exceed PHP_INT_MAX.-1, -42, -999999🔢 Numbers
no-whitespace-stringString containing none of PHP trim()'s default whitespace characters.hello, abc123, foo-bar🔤 Simple string format
non-empty-list<T>Non-empty list (consecutive integer keys starting at 0). T is optional; when provided, each element must match T (scalar types like int, float, etc., or class/interface references).non-empty-list<int>, non-empty-list<DateTimeInterface>, non-empty-list📦 Collections
non-empty-when-trimmed-stringString whose value is non-empty after applying PHP trim() with default characters.hello, x, 123🔤 Simple string format
non-negative-floatFloat greater than or equal to 0.0. Decide whether negative zero (-0.0) is accepted.0.0, 0.5, 42.1🔢 Numbers
non-negative-int-as-stringCanonical integer string with a value >= 0. Cannot be expected to be reliably converted to int because the value may exceed PHP_INT_MAX. Does not accept scientific notation.0, 1, 42, 999999🔢 Numbers
non-positive-floatFloat less than or equal to 0.0. Decide whether negative zero (-0.0) is accepted.0.0, -0.5, -42.1🔢 Numbers
non-positive-int-as-stringCanonical integer string with a value <= 0. Cannot be expected to be reliably converted to int because the value may exceed PHP_INT_MIN. Does not accept scientific notation.0, -1, -42, -999999🔢 Numbers
odd-intInteger not divisible by 2.1, -1, 3, 41🔢 Numbers
pascal-case-stringPascalCase identifier beginning with an uppercase ASCII letter.FooBar, ApiClient, MyVariable1🔤 Simple string format
port-stringTCP/UDP port number represented as a string in the range 0–65535.80, 443, 8080, 65535🖧 Network
positive-floatFloat strictly greater than 0.0.0.1, 1.5, 42.0🔢 Numbers
positive-int-as-stringCanonical positive integer string excluding zero. Cannot be expected to be reliably converted to int because the value may exceed PHP_INT_MIN. Does not accept scientific notation.1, 42, 999999🔢 Numbers
power-of-two-intPositive integer that is an exact power of two.1, 2, 4, 8, 1024🔢 Numbers
private-ip-stringPrivate IPv4 or IPv6 address (RFC 1918 IPv4 or RFC 4193 Unique Local IPv6). Intended for intersections like ip-string&private-ip-string, ipv4-string&private-ip-string, or ipv6-string&private-ip-string.10.0.0.1, 192.168.1.1, fd12:3456:789a::1🖧 Network
public-ip-stringPublic IPv4 or IPv6 address (non-private and non-reserved). Intended for intersections like ip-string&public-ip-string, ipv4-string&public-ip-string, or ipv6-string&public-ip-string.8.8.8.8, 1.1.1.1, 2001:4860:4860::8888🖧 Network
semver-stringValid semantic version string.1.0.0, 2.1.3-beta, 1.2.3+build5🔤 Simple string format
sha1-stringExactly 40 lowercase hexadecimal characters.da39a3ee5e6b4b0d3255bfef95601890afd80709🔀 Encoding
sha256-stringExactly 64 lowercase hexadecimal characters.e3b0c44298fc1c149afbf4c8996fb924...🔀 Encoding
sha512-stringExactly 128 lowercase hexadecimal characters.cf83e1357eefb8bdf1542850d66d8007...🔀 Encoding
shouted-snake-case-stringUppercase snake-case identifier.FOO, FOO_BAR, API_V2_KEY🔤 Simple string format
slug-stringURL/path-friendly lowercase slug.hello-world, my-blog-post, abc123🔗 URI
snake-case-stringLowercase snake-case identifier.foo, foo_bar, api_v2_key🔤 Simple string format
string-length-between<M,N>String whose character length (multibyte-safe) is between M and N inclusive, where 0 <= M <= N.string-length-between<1,255>, string-length-between<8,8>, string-length-between<0,100>🔤 Simple string format
subnet-maskValid IPv4 subnet mask with contiguous leading 1 bits and trailing 0 bits.255.255.255.0, 255.255.0.0, 255.255.255.255🖧 Network
tel-uri-stringRFC 3966 tel: URI identifying a telephone resource; supports both global numbers (E.164 with +) and local numbers.tel:+4512345678, tel:+14155552671, tel:0800-12345☎️ Telephony
🔗 URI
timezone-stringValid IANA timezone identifier.UTC, Europe/Copenhagen, America/New_York📅 Date 🕒 Time
trimmed-non-empty-stringNon-empty string with no leading or trailing PHP trim() default whitespace.hello, abc123, foo bar🔤 Simple string format
ulid-stringValid ULID string as accepted by Symfony\Component\Uid\Ulid::isValid(...).01ARZ3NDEKTSV4RRFFQ69G5FAV🆔 Identification
uri-stringSyntactically valid RFC 3986 URI (including relative references) as accepted by League\Uri\Uri::createFromString(...).mailto:test@example.com, /relative/path, https://example.com, http://smørrebrød.dk🔗 URI
url-stringAbsolute HTTP or HTTPS URL with valid host and optional port/path/query/fragment, as accepted by League\Uri\Uri::createFromString(...).https://example.com, http://localhost:8080, https://api.example.com/v1, http://smørrebrød.dk🔗 URI
🌐 Web/HTTP
urn-stringRFC 8141 URN with the urn scheme, a namespace identifier, and a non-empty namespace-specific string.urn:isbn:0451450523, urn:uuid:6ba7b810-9dad-11d1-80b4-00c04fd430c8, urn:ietf:rfc:8141🔗 URI
🆔 Identification
uuid-stringValid UUID string as accepted by Ramsey\Uuid\Uuid::isValid(...).550e8400-e29b-41d4-a716-446655440000🆔 Identification
uuid1-stringValid UUID string with version 1 specifically.6ba7b810-9dad-11d1-80b4-00c04fd430c8🆔 Identification
uuid3-stringValid UUID string with version 3 specifically.6fa459ea-ee8a-3ca4-894e-db77e160355e🆔 Identification
uuid4-stringValid UUID string with version 4 specifically.550e8400-e29b-41d4-a716-446655440000🆔 Identification
uuid5-stringValid UUID string with version 5 specifically.21f7f8de-8051-5b89-8680-0195ef798b6a🆔 Identification
uuid6-stringValid UUID string with version 6 specifically.1ec9414c-232a-6b00-b3c8-9e6bdeced846🆔 Identification
uuid7-stringValid UUID string with version 7 specifically.01890f47-6c4c-7b3d-bc44-5b6d1e4f8c92🆔 Identification
uuid8-stringValid UUID string with version 8 specifically.2489e9ad-2ee2-8e00-8ec9-32d5f69181c0🆔 Identification
webhook-urlAbsolute HTTP or HTTPS URL with a required host and no fragment (#...) part.https://example.com/webhooks/inbound, http://localhost:8080/hook?token=abc123, https://api.example.com/hook🔗 URI
🌐 Web/HTTP

License & Disclaimer

Licensed under the MIT License. See LICENSE. Basically: Use this library at your own risk.

Contributing

We prefer that you create an issue and or a merge request at https://gitlab.com/eboreum/phpstan-types, and have a discussion about a feature or bug here.

Credits

Authors

Vibe-coded

DISCLAIMER: Parts of this code base has been made using AI, namely GPT-5.5! Although, there was an adult in the room during this process.

统计信息

  • 总下载量: 0
  • 月度下载量: 0
  • 日度下载量: 0
  • 收藏数: 0
  • 点击次数: 14
  • 依赖项目数: 0
  • 推荐数: 0

GitHub 信息

  • Stars: 0
  • Watchers: 0
  • Forks: 0
  • 开发语言: PHP

其他信息

  • 授权协议: MIT
  • 更新时间: 2026-05-11

承接程序开发

PHP开发

VUE

Vue开发

前端开发

小程序开发

公众号开发

系统定制

数据库设计

云部署

网站建设

安全加固