国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

Maison Applet WeChat Développement WeChat Introduction détaillée à l'utilisation du développement backend Yii2 WeChat

Introduction détaillée à l'utilisation du développement backend Yii2 WeChat

Mar 19, 2017 pm 06:07 PM

Yii2 est un framework PHP hautes performances basé sur des composants. Cet article vous présente en détail le développement du backend WeChat à l'aide de Yii2. Jetons un coup d'oeil.

Il existe de nombreux tutoriels sur le développement YII2.0 WeChat sur Internet, mais ils sont trop compliqués et compliqués, je vais donc résumer aujourd'hui la série de développement utilisant le backend Yii2 WeChat pour votre référence.

1?: Accédez à WeChat

Configuration en arrière-plan Yii2

1 Dans Configurer. paramètres du jeton dans app/config/params.php

return [
 //微信接入
 'wechat' =>[
 'token' => 'your token',
 ],
];

2. Configurez le routage dans app/config/main.php

Le module d'interface utilisant l'API RESTful, des règles de routage doivent être définies.

'urlManager' => [
 'enablePrettyUrl' => true,
 'enableStrictParsing' => true,
 'showScriptName' => false,
 'rules' => [
 [
  'class' => 'yii\rest\UrlRule',
  'controller' => 'wechat',
  'extraPatterns' => [
  'GET valid' => 'valid',
  ],
 ],
 ],
],

3. Créez un nouveau WechatController dans l'application/les contr?leurs

<?php

namespace api\controllers;

use Yii;
use yii\rest\ActiveController;

class WechatController extends ActiveController
{

 public $modelClass = &#39;&#39;;

 public function actionValid()
 {
 $echoStr = $_GET["echostr"];
 $signature = $_GET["signature"];
 $timestamp = $_GET["timestamp"];
 $nonce = $_GET["nonce"];
 //valid signature , option
 if($this->checkSignature($signature,$timestamp,$nonce)){
  echo $echoStr;
 }
 }

 private function checkSignature($signature,$timestamp,$nonce)
 {
 // you must define TOKEN by yourself
 $token = Yii::$app->params[&#39;wechat&#39;][&#39;token&#39;];
 if (!$token) {
  echo &#39;TOKEN is not defined!&#39;;
 } else {
  $tmpArr = array($token, $timestamp, $nonce);
  // use SORT_STRING rule
  sort($tmpArr, SORT_STRING);
  $tmpStr = implode( $tmpArr );
  $tmpStr = sha1( $tmpStr );

  if( $tmpStr == $signature ){
  return true;
  }else{
  return false;
  }
 }
 }

}

Configuration en arrière-plan du compte officiel WeChat

Configurez l'URL et le jeton dans l'arrière-plan du compte officiel WeChat, puis soumettez-les pour vérification.

URL:http://app.demo.com/wechats/valid
Token:your token

Deux?: Obtenir des informations sur l'utilisateur

Conception de la table utilisateur

Le code est le suivant :

CREATE TABLE `wechat_user` (
  `id` int(11) NOT NULL,
  `openid` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `nickname` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT &#39;微信昵稱&#39;,
  `sex` tinyint(4) NOT NULL COMMENT &#39;性別&#39;,
  `headimgurl` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT &#39;頭像&#39;,
  `country` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT &#39;國家&#39;,
  `province` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT &#39;省份&#39;,
  `city` varchar(50) COLLATE utf8_unicode_ci NOT NULL COMMENT &#39;城市&#39;,
  `access_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `refresh_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL,
  `created_at` timestamp NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
ALTER TABLE `wechat_user`
  ADD PRIMARY KEY (`id`);

Interfaces associées pour obtenir des informations utilisateur

1. Interface d'autorisation utilisateur : obtenir access_token, openId, etc. obtenir et enregistrer les informations utilisateur Dans la base de données

le code est le suivant?:

public function actionAccesstoken()
{
    $code = $_GET["code"];
    $state = $_GET["state"];
    $appid = Yii::$app->params[&#39;wechat&#39;][&#39;appid&#39;];
    $appsecret = Yii::$app->params[&#39;wechat&#39;][&#39;appsecret&#39;];
    $request_url = &#39;https://api.weixin.qq.com/sns/oauth2/access_token?appid=&#39;.$appid.&#39;&secret=&#39;.$appsecret.&#39;&code=&#39;.$code.&#39;&grant_type=authorization_code&#39;;
    //初始化一個(gè)curl會(huì)話
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $request_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    $result = $this->response($result);
    //獲取token和openid成功,數(shù)據(jù)解析
    $access_token = $result[&#39;access_token&#39;];
    $refresh_token = $result[&#39;refresh_token&#39;];
    $openid = $result[&#39;openid&#39;];
    //請(qǐng)求微信接口,獲取用戶信息
    $userInfo = $this->getUserInfo($access_token,$openid);
    $user_check = WechatUser::find()->where([&#39;openid&#39;=>$openid])->one();
    if ($user_check) {
        //更新用戶資料
    } else {
        //保存用戶資料
    }
    //前端網(wǎng)頁的重定向
    if ($openid) {
        return $this->redirect($state.$openid);
    } else {
        return $this->redirect($state);
    }
}

2. Obtenir les informations utilisateur de WeChat

le code est le suivant :

public function getUserInfo($access_token,$openid)
{
    $request_url = &#39;https://api.weixin.qq.com/sns/userinfo?access_token=&#39;.$access_token.&#39;&openid=&#39;.$openid.&#39;&lang=zh_CN&#39;;
    //初始化一個(gè)curl會(huì)話
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $request_url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $result = curl_exec($ch);
    curl_close($ch);
    $result = $this->response($result);
    return $result;
}

3. Obtenir l'interface des informations utilisateur

public function actionUserinfo()
{
 if(isset($_REQUEST["openid"])){
  $openid = $_REQUEST["openid"];
  $user = WechatUser::find()->where([&#39;openid&#39;=>$openid])->one();
  if ($user) {
   $result[&#39;error&#39;] = 0;
   $result[&#39;msg&#39;] = &#39;獲取成功&#39;;
   $result[&#39;user&#39;] = $user;
  } else {
   $result[&#39;error&#39;] = 1;
   $result[&#39;msg&#39;] = &#39;沒有該用戶&#39;;
  }
 } else {
  $result[&#39;error&#39;] = 1;
  $result[&#39;msg&#39;] = &#39;openid為空&#39;;
 }
 return $result;
}

Trois?: paiement WeChat

1. Interface de paiement WeChat?: données de paiement packagées

Le code est le suivant?:

public function actionPay(){
    if(isset($_REQUEST["uid"])&&isset($_REQUEST["oid"])&&isset($_REQUEST["totalFee"])){
        //uid、oid、totalFee
        $uid = $_REQUEST["uid"];
        $oid = $_REQUEST["oid"];
        $totalFee = $_REQUEST["totalFee"];
        $timestamp = time();
        //微信支付參數(shù)
        $appid = Yii::$app->params[&#39;wechat&#39;][&#39;appid&#39;];
        $mchid = Yii::$app->params[&#39;wechat&#39;][&#39;mchid&#39;];
        $key = Yii::$app->params[&#39;wechat&#39;][&#39;key&#39;];
        $notifyUrl = Yii::$app->params[&#39;wechat&#39;][&#39;notifyUrl&#39;];
        //支付打包
        $wx_pay = new WechatPay($mchid, $appid, $key);
        $package = $wx_pay->createJsBizPackage($uid, $totalFee, $oid, $notifyUrl, $timestamp);
        $result[&#39;error&#39;] = 0;
        $result[&#39;msg&#39;] = &#39;支付打包成功&#39;;
        $result[&#39;package&#39;] = $package;
        return $result;
    }else{
        $result[&#39;error&#39;] = 1;
        $result[&#39;msg&#39;] = &#39;請(qǐng)求參數(shù)錯(cuò)誤&#39;;
    }
    return $result;
}

2. Recevez le paiement asynchrone envoyé par notification de résultat WeChat

Le code est le suivant?:

public function actionNotify(){
    $postStr = $GLOBALS["HTTP_RAW_POST_DATA"];
    $postObj = simplexml_load_string($postStr, &#39;SimpleXMLElement&#39;, LIBXML_NOCDATA);
    //
    if ($postObj === false) {
        die(&#39;parse xml error&#39;);
    }
    if ($postObj->return_code != &#39;SUCCESS&#39;) {
        die($postObj->return_msg);
    }
    if ($postObj->result_code != &#39;SUCCESS&#39;) {
        die($postObj->err_code);
    }
    //微信支付參數(shù)
    $appid = Yii::$app->params[&#39;wechat&#39;][&#39;appid&#39;];
    $mchid = Yii::$app->params[&#39;wechat&#39;][&#39;mchid&#39;];
    $key = Yii::$app->params[&#39;wechat&#39;][&#39;key&#39;];
    $wx_pay = new WechatPay($mchid, $appid, $key);
    //驗(yàn)證簽名
    $arr = (array)$postObj;
    unset($arr[&#39;sign&#39;]);
    if ($wx_pay->getSign($arr, $key) != $postObj->sign) {
        die("簽名錯(cuò)誤");
    }
    //支付處理正確-判斷是否已處理過支付狀態(tài)
    $orders = Order::find()->where([&#39;uid&#39;=>$postObj->openid, &#39;oid&#39;=>$postObj->out_trade_no, &#39;status&#39; => 0])->all();
    if(count($orders) > 0){
        //更新訂單狀態(tài)
        foreach ($orders as $order) {
            //更新訂單
            $order[&#39;status&#39;] = 1;
            $order->update();
        }
        return &#39;<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>&#39;;
    } else {
        //訂單狀態(tài)已更新,直接返回
        return &#39;<xml><return_code><![CDATA[SUCCESS]]></return_code><return_msg><![CDATA[OK]]></return_msg></xml>&#39;;
    }
}

3. .php

Le code est le suivant :

<?php
namespace api\sdk;
use Yii;
class WechatPay
{
    protected $mchid;
    protected $appid;
    protected $key;
    public function __construct($mchid, $appid, $key){
        $this->mchid = $mchid;
        $this->appid = $appid;
        $this->key = $key;
    }
    public function createJsBizPackage($openid, $totalFee, $outTradeNo, $orderName, $notifyUrl, $timestamp){
        $config = array(
            &#39;mch_id&#39; => $this->mchid,
            &#39;appid&#39; => $this->appid,
            &#39;key&#39; => $this->key,
        );
        $unified = array(
            &#39;appid&#39; => $config[&#39;appid&#39;],
            &#39;attach&#39; => &#39;支付&#39;,
            &#39;body&#39; => $orderName,
            &#39;mch_id&#39; => $config[&#39;mch_id&#39;],
            &#39;nonce_str&#39; => self::createNonceStr(),
            &#39;notify_url&#39; => $notifyUrl,
            &#39;openid&#39; => $openid,
            &#39;out_trade_no&#39; => $outTradeNo,
            &#39;spbill_create_ip&#39; => &#39;127.0.0.1&#39;,
            &#39;total_fee&#39; => intval($totalFee * 100),
            &#39;trade_type&#39; => &#39;JSAPI&#39;,
        );
        $unified[&#39;sign&#39;] = self::getSign($unified, $config[&#39;key&#39;]);
        $responseXml = self::curlPost(&#39;https://api.mch.weixin.qq.com/pay/unifiedorder&#39;, self::arrayToXml($unified));
        $unifiedOrder = simplexml_load_string($responseXml, &#39;SimpleXMLElement&#39;, LIBXML_NOCDATA);
        if ($unifiedOrder === false) {
            die(&#39;parse xml error&#39;);
        }
        if ($unifiedOrder->return_code != &#39;SUCCESS&#39;) {
            die($unifiedOrder->return_msg);
        }
        if ($unifiedOrder->result_code != &#39;SUCCESS&#39;) {
            die($unifiedOrder->err_code);
        }
        $arr = array(
            "appId" => $config[&#39;appid&#39;],
            "timeStamp" => $timestamp,
            "nonceStr" => self::createNonceStr(),
            "package" => "prepay_id=" . $unifiedOrder->prepay_id,
            "signType" => &#39;MD5&#39;,
        );
        $arr[&#39;paySign&#39;] = self::getSign($arr, $config[&#39;key&#39;]);
        return $arr;
    }
    public static function curlGet($url = &#39;&#39;, $options = array()){
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        if (!empty($options)) {
            curl_setopt_array($ch, $options);
        }
        //https請(qǐng)求 不驗(yàn)證證書和host
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }
    public static function curlPost($url = &#39;&#39;, $postData = &#39;&#39;, $options = array()){
        if (is_array($postData)) {
            $postData = http_build_query($postData);
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30); //設(shè)置cURL允許執(zhí)行的最長秒數(shù)
        if (!empty($options)) {
            curl_setopt_array($ch, $options);
        }
        //https請(qǐng)求 不驗(yàn)證證書和host
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }
    public static function createNonceStr($length = 16){
        $chars = &#39;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&#39;;
        $str = &#39;&#39;;
        for ($i = 0; $i<$length; $i++){
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }
    public static function arrayToXml($arr){
        $xml = "<xml>";
        foreach ($arr as $key => $val){
            if (is_numeric($val)) {
                $xml .= "<" . $key . ">" . $val . "</" . $key . ">";
            } else {
                $xml .= "<" . $key . "><![CDATA[" . $val . "]]></" . $key . ">";
            }
        }
        $xml .= "</xml>";
        return $xml;
    }
    public static function getSign($params, $key){
        ksort($params, SORT_STRING);
        $unSignParaString = self::formatQueryParaMap($params, false);
        $signStr = strtoupper(md5($unSignParaString . "&key=" . $key));
        return $signStr;
    }
    protected static function formatQueryParaMap($paraMap, $urlEncode = false){
        $buff = "";
        ksort($paraMap);
        foreach ($paraMap as $k => $v){
            if (null != $v && "null" != $v) {
                if ($urlEncode) {
                    $v = urlencode($v);
                }
                $buff .= $k . "=" . $v . "&";
            }
        }
        $reqPar = &#39;&#39;;
        if (strlen($buff)>0) {
            $reqPar = substr($buff, 0, strlen($buff) - 1);
        }
        return $reqPar;
    }
}

Quatre : Obtenir les paramètres de configuration du JS-SDK

Selon la documentation du développeur de la plateforme publique WeChat?:

Tous doivent utiliser JS -La page SDK doit d'abord injecter des informations de configuration, sinon elle ne sera pas appelée (la même URL ne doit être appelée qu'une seule fois . L'application Web SPA qui modifie l'URL peut être appelée à chaque fois que l'URL change. Actuellement, le client Android WeChat ne prend pas en charge pushState H5, donc l'utilisation de pushState pour implémenter les pages de l'application Web entra?nera un échec de signature. sera corrigé dans Android 6.2).

C'est-à-dire?:

Le code est le suivant?:

wx.config({
    debug: true, // 開啟調(diào)試模式,調(diào)用的所有api的返回值會(huì)在客戶端alert出來,若要查看傳入的參數(shù),可以在pc端打開,參數(shù)信息會(huì)通過log打出,僅在pc端時(shí)才會(huì)打印。
    appId: &#39;&#39;, // 必填,公眾號(hào)的唯一標(biāo)識(shí)
    timestamp: , // 必填,生成簽名的時(shí)間戳
    nonceStr: &#39;&#39;, // 必填,生成簽名的隨機(jī)串
    signature: &#39;&#39;,// 必填,簽名,見附錄1
    jsApiList: [] // 必填,需要使用的JS接口列表,所有JS接口列表見附錄2
});

1. Classe de paiement Wechat WechatPay.php

Le code est le suivant?:

<?php
namespace api\sdk;
use Yii;
class WechatPay
{
    public function getSignPackage($url) {
        $jsapiTicket = self::getJsApiTicket();
        $timestamp = time();
        $nonceStr = self::createNonceStr();
        // 這里參數(shù)的順序要按照 key 值 ASCII 碼升序排序
        $string = "jsapi_ticket=".$jsapiTicket."&noncestr=".$nonceStr."&timestamp=".$timestamp."&url=".$url;
        $signature = sha1($string);
        $signPackage = array(
            "appId"     => $this->appid,
            "nonceStr"  => $nonceStr,
            "timestamp" => $timestamp,
            "url"       => $url,
            "signature" => $signature,
            "rawString" => $string
        );
        return $signPackage;
    }
    public static function getJsApiTicket() {
        //使用Redis緩存 jsapi_ticket
        $redis = Yii::$app->redis;
        $redis_ticket = $redis->get(&#39;wechat:jsapi_ticket&#39;);
        if ($redis_ticket) {
            $ticket = $redis_ticket;
        } else {
            $accessToken = self::getAccessToken();
            $url = "https://api.weixin.qq.com/cgi-bin/ticket/getticket?type=jsapi&access_token=".$accessToken;
            $res = json_decode(self::curlGet($url));
            $ticket = $res->ticket;
            if ($ticket) {
                $redis->set(&#39;wechat:jsapi_ticket&#39;, $ticket);
                $redis->expire(&#39;wechat:jsapi_ticket&#39;, 7000);
            }
        }
        return $ticket;
    }
    public static function getAccessToken() {
        //使用Redis緩存 access_token
        $redis = Yii::$app->redis;
        $redis_token = $redis->get(&#39;wechat:access_token&#39;);
        if ($redis_token) {
            $access_token = $redis_token;
        } else {
            $appid = Yii::$app->params[&#39;wechat&#39;][&#39;appid&#39;];
            $appsecret = Yii::$app->params[&#39;wechat&#39;][&#39;appsecret&#39;];
            $url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$appid."&secret=".$appsecret;
            $res = json_decode(self::curlGet($url));
            $access_token = $res->access_token;
            if ($access_token) {
                $redis->set(&#39;wechat:access_token&#39;, $access_token);
                $redis->expire(&#39;wechat:access_token&#39;, 7000);
            }
        }
        return $access_token;
    }
    public static function curlGet($url = &#39;&#39;, $options = array()){
        $ch = curl_init($url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        if (!empty($options)) {
            curl_setopt_array($ch, $options);
        }
        //https請(qǐng)求 不驗(yàn)證證書和host
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }
    public static function curlPost($url = &#39;&#39;, $postData = &#39;&#39;, $options = array()){
        if (is_array($postData)) {
            $postData = http_build_query($postData);
        }
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $postData);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30); //設(shè)置cURL允許執(zhí)行的最長秒數(shù)
        if (!empty($options)) {
            curl_setopt_array($ch, $options);
        }
        //https請(qǐng)求 不驗(yàn)證證書和host
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
    }
    public static function createNonceStr($length = 16){
        $chars = &#39;abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789&#39;;
        $str = &#39;&#39;;
        for ($i = 0; $i<$length; $i++){
            $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
        }
        return $str;
    }
}

2. Obtenez l'interface des paramètres de configuration

public function actionConfig(){
 if (isset($_REQUEST[&#39;url&#39;])) {
 $url = $_REQUEST[&#39;url&#39;];
 //微信支付參數(shù)
 $appid = Yii::$app->params[&#39;wechat&#39;][&#39;appid&#39;];
 $mchid = Yii::$app->params[&#39;wechat&#39;][&#39;mchid&#39;];
 $key = Yii::$app->params[&#39;wechat&#39;][&#39;key&#39;];
 $wx_pay = new WechatPay($mchid, $appid, $key);
 $package = $wx_pay->getSignPackage($url);
 $result[&#39;error&#39;] = 0;
 $result[&#39;msg&#39;] = &#39;獲取成功&#39;;
 $result[&#39;config&#39;] = $package;
 } else {
 $result[&#39;error&#39;] = 1;
 $result[&#39;msg&#39;] = &#39;參數(shù)錯(cuò)誤&#39;;
 }
 return $result;
}

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefa?on, veuillez contacter admin@php.cn

Outils d'IA chauds

Undress AI Tool

Undress AI Tool

Images de déshabillage gratuites

Undresser.AI Undress

Undresser.AI Undress

Application basée sur l'IA pour créer des photos de nu réalistes

AI Clothes Remover

AI Clothes Remover

Outil d'IA en ligne pour supprimer les vêtements des photos.

Clothoff.io

Clothoff.io

Dissolvant de vêtements AI

Video Face Swap

Video Face Swap

échangez les visages dans n'importe quelle vidéo sans effort grace à notre outil d'échange de visage AI entièrement gratuit?!

Outils chauds

Bloc-notes++7.3.1

Bloc-notes++7.3.1

éditeur de code facile à utiliser et gratuit

SublimeText3 version chinoise

SublimeText3 version chinoise

Version chinoise, très simple à utiliser

Envoyer Studio 13.0.1

Envoyer Studio 13.0.1

Puissant environnement de développement intégré PHP

Dreamweaver CS6

Dreamweaver CS6

Outils de développement Web visuel

SublimeText3 version Mac

SublimeText3 version Mac

Logiciel d'édition de code au niveau de Dieu (SublimeText3)

Sujets chauds

Tutoriel PHP
1502
276