搜索
首页后端开发php教程YII如何使用kindeditor扩展
YII如何使用kindeditor扩展Jan 02, 2018 pm 01:08 PM
kindeditor使用扩展

YII如何使用kindeditor扩展?本文主要介绍了YII视图整合kindeditor扩展的方法,较为详细的分析了Yii框架整合kindeditor的功能实现代码与设置相关技巧,需要的朋友可以参考下。希望对大家有所帮助。

具体如下:

比较喜欢用kindeditor,YII上的版本比较旧,所以自己重新整了个扩展
先在protected\extensions下创建KEditor文件夹用来放文件,keSource里放kindeditor的源文件,然后建三个类KEditor、KEditorManage和KEditorUpload,KEditor是扩展的主文件,KEditorManage是用来浏览服务器文件的,KEditorUpload是用来示例接收上传文件的,

KEditor代码

<?php
class KEditor extends CWidget{
  /*
   * TEXTAREA输入框的属性,保证js调用KE失败时,文本框的样式。
   */
  public $textareaOptions=array();
  /*
   * 编辑器属性集。
   */
  public $properties=array();
  /*
   * TEXTAREA输入框的name,必须设置。
   * 数据类型:String
   */
  public $name;
  /*
   * TEXTAREA的id,可为空
   */
  public $id;
  public $model;
  public $baseUrl;
  public static function getUploadPath(){
    $dir = dirname(__FILE__).DIRECTORY_SEPARATOR.&#39;keSource&#39;;
    if(isset(Yii::app()->params->uploadPath)){
      return Yii::getPathOfAlias(&#39;webroot&#39;).str_replace(
                &#39;/&#39;,DIRECTORY_SEPARATOR,
                Yii::app()->params->
                uploadPath);
    }
    return Yii::app()->getAssetmanager()
        ->getPublishedPath($dir).DIRECTORY_SEPARATOR.&#39;upload&#39;;
  }
  public static function getUploadUrl(){
    $dir = dirname(__FILE__).DIRECTORY_SEPARATOR.&#39;keSource&#39;;
    if(isset(Yii::app()->params->uploadPath)){
      return Yii::app()->baseUrl.Yii::app()->params->uploadPath;
    }
    return Yii::app()->getAssetManager()->publish($dir).&#39;/upload&#39;;
  }
  public function init(){
    if($this->name===null)
      throw new CException(Yii::t(&#39;zii&#39;,&#39;The id property cannot be empty.&#39;));
    $dir = dirname(__FILE__).DIRECTORY_SEPARATOR.&#39;keSource&#39;;
    $this->baseUrl=Yii::app()->getAssetManager()->publish($dir);
    $cs=Yii::app()->getClientScript();
    $cs->registerCssFile($this->baseUrl.&#39;/themes/default/default.css&#39;);
    if(YII_DEBUG) $cs->registerScriptFile($this->baseUrl.&#39;/kindeditor.js&#39;);
    else $cs->registerScriptFile($this->baseUrl.&#39;/kindeditor-min.js&#39;);
  }
  public function run(){
    $cs=Yii::app()->getClientScript();
    $textAreaOptions=$this->gettextareaOptions();
    $textAreaOptions[&#39;name&#39;]=CHtml::resolveName($this->model,$this->name);
    $this->id=$textAreaOptions[&#39;id&#39;]=CHtml::getIdByName($textAreaOptions[&#39;name&#39;]);
    echo CHtml::activeTextArea($this->model,$this->name,$textAreaOptions);
    $properties_string = CJavaScript::encode($this->getKeProperties());
    $js=<<<EOF
KindEditor.ready(function(K) {
  var editor_$this->id = K.create(&#39;#$this->id&#39;,
$properties_string
  );
});
EOF;
    $cs->registerScript(&#39;KE&#39;.$this->name,$js,CClientScript::POS_HEAD);
  }
  public function gettextareaOptions(){
    //允许获取的属性
    $allowParams=array(&#39;rows&#39;,&#39;cols&#39;,&#39;style&#39;);
    //准备返回的属性数组
    $params=array();
    foreach($allowParams as $key){
      if(isset($this->textareaOptions[$key]))
        $params[$key]=$this->textareaOptions[$key];
    }
    $params[&#39;name&#39;]=$params[&#39;id&#39;]=$this->name;
    return $params;
  }
  public function getKeProperties(){
    $properties_key=array(
      &#39;width&#39;,
      &#39;height&#39;,
      &#39;minWidth&#39;,
      &#39;minHeight&#39;,
      &#39;items&#39;,
      &#39;noDisableItems&#39;,
      &#39;filterMode&#39;,
      &#39;htmlTags&#39;,
      &#39;wellFormatMode&#39;,
      &#39;resizeType&#39;,
      &#39;themeType&#39;,
      &#39;langType&#39;,
      &#39;designMode&#39;,
      &#39;fullscreenMode&#39;,
      &#39;basePath&#39;,
      &#39;themesPath&#39;,
      &#39;pluginsPath&#39;,
      &#39;langPath&#39;,
      &#39;minChangeSize&#39;,
      &#39;urlType&#39;,
      &#39;newlineTag&#39;,
      &#39;pasteType&#39;,
      &#39;dialogAlignType&#39;,
      &#39;shadowMode&#39;,
      &#39;useContextmenu&#39;,
      &#39;syncType&#39;,
      &#39;indentChar&#39;,
      &#39;cssPath&#39;,
      &#39;cssData&#39;,
      &#39;bodyClass&#39;,
      &#39;colorTable&#39;,
      &#39;afterCreate&#39;,
      &#39;afterChange&#39;,
      &#39;afterTab&#39;,
      &#39;afterFocus&#39;,
      &#39;afterBlur&#39;,
      &#39;afterUpload&#39;,
      &#39;uploadJson&#39;,
      &#39;fileManagerJson&#39;,
      &#39;allowPreviewEmoticons&#39;,
      &#39;allowImageUpload&#39;,
      &#39;allowFlashUpload&#39;,
      &#39;allowMediaUpload&#39;,
      &#39;allowFileUpload&#39;,
      &#39;allowFileManager&#39;,
      &#39;fontSizeTable&#39;,
      &#39;imageTabIndex&#39;,
      &#39;formatUploadUrl&#39;,
      &#39;fullscreenShortcut&#39;,
      &#39;extraFileUploadParams&#39;,
    );
    //准备返回的属性数组
    $params=array();
    foreach($properties_key as $key){
      if(isset($this->properties[$key]))
        $params[$key]=$this->properties[$key];
    }
    return $params;
  }
}

KEditorManage代码


<?php
class KEditorManage extends CAction{
  public function run(){
    Yii::import(&#39;ext.KEditor.KEditor&#39;);
    $root_path=KEditor::getUploadPath().&#39;/&#39;;
    $root_url=KEditor::getUploadUrl().&#39;/&#39;;
    //图片扩展名
    $ext_arr = array(&#39;gif&#39;, &#39;jpg&#39;, &#39;jpeg&#39;, &#39;png&#39;, &#39;bmp&#39;);
    //目录名
    $dir_name = empty($_GET[&#39;dir&#39;]) ? &#39;&#39; : trim($_GET[&#39;dir&#39;]);
    if (!in_array($dir_name, array(&#39;&#39;, &#39;image&#39;, &#39;flash&#39;, &#39;media&#39;, &#39;file&#39;))) {
      echo "Invalid Directory name.";
      exit;
    }
    if ($dir_name !== &#39;&#39;) {
      $root_path .= $dir_name . "/";
      $root_url .= $dir_name . "/";
      if (!file_exists($root_path)) {
        mkdir($root_path);
      }
    }
    //根据path参数,设置各路径和URL
    if (empty($_GET[&#39;path&#39;])) {
      $current_path = realpath($root_path) . &#39;/&#39;;
      $current_url = $root_url;
      $current_dir_path = &#39;&#39;;
      $moveup_dir_path = &#39;&#39;;
    } else {
      $current_path = realpath($root_path) . &#39;/&#39; . $_GET[&#39;path&#39;];
      $current_url = $root_url . $_GET[&#39;path&#39;];
      $current_dir_path = $_GET[&#39;path&#39;];
      $moveup_dir_path = preg_replace(&#39;/(.*?)[^\/]+\/$/&#39;, &#39;$1&#39;, $current_dir_path);
    }
    echo realpath($root_path);
    //排序形式,name or size or type
    $order = empty($_GET[&#39;order&#39;]) ? &#39;name&#39; : strtolower($_GET[&#39;order&#39;]);
    //不允许使用..移动到上一级目录
    if (preg_match(&#39;/\.\./&#39;, $current_path)) {
      echo &#39;Access is not allowed.&#39;;
      exit;
    }
    //最后一个字符不是/
    if (!preg_match(&#39;/\/$/&#39;, $current_path)) {
      echo &#39;Parameter is not valid.&#39;;
      exit;
    }
    //目录不存在或不是目录
    if (!file_exists($current_path) || !is_dir($current_path)) {
      echo &#39;Directory does not exist.&#39;;
      exit;
    }
    //遍历目录取得文件信息
    $file_list = array();
    $handle = new DirectoryIterator($current_path);
    $i=0;
    foreach($handle as $file){
      if($file->isDot()) continue;
      if($file->isDir()){
        $file_list[$i][&#39;is_dir&#39;] = true; //是否文件夹
        $file_list[$i][&#39;has_file&#39;] = (count(scandir($file->getPath())) > 2); //文件夹是否包含文件
        $file_list[$i][&#39;filesize&#39;] = 0; //文件大小
        $file_list[$i][&#39;is_photo&#39;] = false; //是否图片
        $file_list[$i][&#39;filetype&#39;] = &#39;&#39;; //文件类别,用扩展名判断
      }else{
        $file_list[$i][&#39;is_dir&#39;] = false;
        $file_list[$i][&#39;has_file&#39;] = false;
        $file_list[$i][&#39;filesize&#39;] = $file->getSize();
        $file_list[$i][&#39;dir_path&#39;] = &#39;&#39;;
        $file_ext = $file->getExtension();
        $file_list[$i][&#39;is_photo&#39;] = in_array($file_ext, $ext_arr);
        $file_list[$i][&#39;filetype&#39;] = $file_ext;
      }
      $file_list[$i][&#39;filename&#39;] = $file->getFilename(); //文件名,包含扩展名
      $file_list[$i][&#39;datetime&#39;] = date(&#39;Y-m-d H:i:s&#39;, $file->getMTime());
      $i++;
    }
    usort($file_list, array($this,&#39;cmp_func&#39;));
    $result = array();
    //相对于根目录的上一级目录
    $result[&#39;moveup_dir_path&#39;] = $moveup_dir_path;
    //相对于根目录的当前目录
    $result[&#39;current_dir_path&#39;] = $current_dir_path;
    //当前目录的URL
    $result[&#39;current_url&#39;] = $current_url;
    //文件数
    $result[&#39;total_count&#39;] = count($file_list);
    //文件列表数组
    $result[&#39;file_list&#39;] = $file_list;
    //输出JSON字符串
    header(&#39;Content-type: application/json; charset=UTF-8&#39;);
    echo CJSON::encode($result);
    exit;
  }
  //排序
  public function cmp_func($a, $b) {
    global $order;
    if ($a[&#39;is_dir&#39;] && !$b[&#39;is_dir&#39;]) {
      return -1;
    } else if (!$a[&#39;is_dir&#39;] && $b[&#39;is_dir&#39;]) {
      return 1;
    } else {
      if ($order == &#39;size&#39;) {
        if ($a[&#39;filesize&#39;] > $b[&#39;filesize&#39;]) {
          return 1;
        } else if ($a[&#39;filesize&#39;] < $b[&#39;filesize&#39;]) {
          return -1;
        } else {
          return 0;
        }
      } else if ($order == &#39;type&#39;) {
        return strcmp($a[&#39;filetype&#39;], $b[&#39;filetype&#39;]);
      } else {
        return strcmp($a[&#39;filename&#39;], $b[&#39;filename&#39;]);
      }
    }
  }
}
?>

KEditorUpload代码

<?php
class KEditorUpload extends CAction{
  public function run(){
    $dir=isset($_GET[&#39;dir&#39;])?trim($_GET[&#39;dir&#39;]):&#39;file&#39;;
    $ext_arr = array(
      &#39;image&#39; => array(&#39;gif&#39;, &#39;jpg&#39;, &#39;jpeg&#39;, &#39;png&#39;, &#39;bmp&#39;),
      &#39;flash&#39; => array(&#39;swf&#39;, &#39;flv&#39;),
      &#39;media&#39; => array(&#39;swf&#39;, &#39;flv&#39;, &#39;mp3&#39;, &#39;wav&#39;, &#39;wma&#39;, &#39;wmv&#39;, &#39;mid&#39;, &#39;avi&#39;, &#39;mpg&#39;, &#39;asf&#39;, &#39;rm&#39;, &#39;rmvb&#39;),
      &#39;file&#39; => array(&#39;doc&#39;, &#39;docx&#39;, &#39;xls&#39;, &#39;xlsx&#39;, &#39;ppt&#39;, &#39;htm&#39;, &#39;html&#39;, &#39;txt&#39;, &#39;zip&#39;, &#39;rar&#39;, &#39;gz&#39;, &#39;bz2&#39;),
    );
    if(empty($ext_arr[$dir])){
      echo CJSON::encode(array(&#39;error&#39;=>1,&#39;message&#39;=>&#39;目录名不正确。&#39;));
      exit;
    }
    $originalurl=&#39;&#39;;
    $filename=&#39;&#39;;
    $date=date(&#39;Ymd&#39;);
    $id=0;
    $max_size=2097152; //2MBs
    $upload_image=CUploadedFile::getInstanceByName(&#39;imgFile&#39;);
    Yii::import(&#39;ext.KEditor.KEditor&#39;);
    $upload_dir=KEditor::getUploadPath().&#39;/&#39;.$dir;
    if(!file_exists($upload_dir)) mkdir($upload_dir);
    $upload_dir=$upload_dir.&#39;/&#39;.$date;
    if(!file_exists($upload_dir)) mkdir($upload_dir);
    $upload_url=KEditor::getUploadUrl().&#39;/&#39;.$dir.&#39;/&#39;.$date;
    if(is_object($upload_image) && get_class($upload_image)===&#39;CUploadedFile&#39;){
      if($upload_image->size > $max_size){
        echo CJSON::encode(array(&#39;error&#39;=>1,&#39;message&#39;=>&#39;上传文件大小超过限制。&#39;));
        exit;
      }
      //新文件名
      $filename=date("YmdHis").&#39;_&#39;.rand(10000, 99999);
      $ext=$upload_image->extensionName;
      if(in_array($ext, $ext_arr[$dir]) === false){
        echo CJSON::encode(array(&#39;error&#39;=>1,&#39;message&#39;=>"上传文件扩展名是不允许的扩展名。\n只允许".implode(&#39;,&#39;,$ext_arr[$dir]).&#39;格式。&#39;));
        exit;
      }
      $uploadfile=$upload_dir.&#39;/&#39;.$filename.&#39;.&#39;.$ext;
      $originalurl=$upload_url.&#39;/&#39;.$filename.&#39;.&#39;.$ext;
      $upload_image->saveAs($uploadfile);
      echo CJSON::encode(array(&#39;error&#39;=>0,&#39;url&#39;=>$originalurl));
    }else{
      echo CJSON::encode(array(&#39;error&#39;=>1,&#39;message&#39;=>&#39;未知错误&#39;));
    }
  }
}

配置config/main.php文件,设置上传文件存放位置

&#39;params&#39;=>array(
    // this is used in contact page
    &#39;adminEmail&#39;=>&#39;webmaster@example.com&#39;,
    &#39;uploadPath&#39;=>&#39;/upload&#39;, //添加这句,upload为存放文件文件夹的名字,自己定义,这里是放在根目录的upload文件夹

设置接收文件和浏览服务器文件的action

public function actions()
{
  return array(
    //在actions下的return array添加下面两句,没有actions的话自己添加
    &#39;upload&#39;=>array(&#39;class&#39;=>&#39;application.extensions.KEditor.KEditorUpload&#39;),
    &#39;manageJson&#39;=>array(&#39;class&#39;=>&#39;application.extensions.KEditor.KEditorManage&#39;),
  );
}

在视图里面使用

<?php $this->widget(&#39;ext.KEditor.KEditor&#39;,array(
  &#39;model&#39;=>$model, //传入form model
  &#39;name&#39;=>&#39;content&#39;, //设置name
  &#39;properties&#39;=>array(
    //设置接收文件上传的action
    &#39;uploadJson&#39;=>&#39;/admin/default/upload&#39;,
    //设置浏览服务器文件的action,这两个就是上面配置在/admin/default的
    &#39;fileManagerJson&#39;=>&#39;/admin/default/manageJson&#39;,
    &#39;newlineTag&#39;=>&#39;br&#39;,
    &#39;allowFileManager&#39;=>true,
    //传值前加js:来标记这些是js代码
    &#39;afterCreate&#39;=>"js:function() {
        K(&#39;#ChapterForm_all_len&#39;).val(this.count());
        K(&#39;#ChapterForm_word_len&#39;).val(this.count(&#39;text&#39;));
      }",
    &#39;afterChange&#39;=>"js:function() {
        K(&#39;#ChapterForm_all_len&#39;).val(this.count());
        K(&#39;#ChapterForm_word_len&#39;).val(this.count(&#39;text&#39;));
      }",
  ),
  &#39;textareaOptions&#39;=>array(
    &#39;style&#39;=>&#39;width:98%;height:400px;&#39;,
  )
));
?>

textareaOptions用来设置textarea的大小和样式,仅支持rows、cols和style
properties的各项跟js设置kindeditor的是一样的,上面的设置与下面用js设置的是一致,kindeditor原来有的项都可以设置

var editor1 = K.create(&#39;#editor_modelname_name&#39;, {
  uploadJson : "/admin/default/upload",
  fileManagerJson : "/admin/default/manageJson",
  newlineTag : "br",
  allowFileManager : true,
  afterCreate : function() {
    K(&#39;#ChapterForm_all_len&#39;).html(this.count());
    K(&#39;#ChapterForm_word_len&#39;).html(this.count(&#39;text&#39;));
  },
  afterChange : function() {
    K(&#39;#ChapterForm_all_len&#39;).html(this.count());
    K(&#39;#ChapterForm_word_len&#39;).html(this.count(&#39;text&#39;));
  }
});

相关推荐:

Yii2的语言包设置

Yii2中的代码自动加载机制

Yii2实现rbac权限控制

以上是YII如何使用kindeditor扩展的详细内容。更多信息请关注PHP中文网其他相关文章!

声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn
php如何使用PHP的SNMP扩展?php如何使用PHP的SNMP扩展?Jun 02, 2023 am 10:22 AM

PHP的SNMP扩展是一种使PHP能够通过SNMP协议与网络设备进行通信的扩展程序。使用该扩展可以方便地获取和修改网络设备的配置信息,例如路由器、交换机等设备的CPU、内存、网络接口等信息,也可以进行诸如开关设备端口等控制操作。本文将介绍SNMP协议的基础知识、PHP的SNMP扩展的安装方法以及如何在PHP中使用SNMP扩展进行网络设备的监控和控制。一、SN

如何使用极光推送扩展,在PHP应用中实现批量消息推送功能如何使用极光推送扩展,在PHP应用中实现批量消息推送功能Jul 25, 2023 pm 08:07 PM

如何使用极光推送扩展,在PHP应用中实现批量消息推送功能在移动应用的开发中,消息推送是一项非常重要的功能。极光推送是一种常用的消息推送服务,提供了丰富的功能和接口。本文将介绍如何使用极光推送扩展在PHP应用中实现批量消息推送功能。第一步:注册极光推送账号并获取API密钥首先,我们需要在极光推送官网(https://www.jiguang.cn/push)注册

php如何使用PHP的ZipArchive扩展?php如何使用PHP的ZipArchive扩展?Jun 02, 2023 am 08:13 AM

PHP是一种流行的服务器端语言,可以用来开发Web应用程序和处理文件。PHP的ZipArchive扩展是一个强大的工具,可以在PHP中操作zip文件。在这篇文章中,我们将介绍如何使用PHP的ZipArchive扩展来创建、读取和修改zip文件。一、安装ZipArchive扩展在使用ZipArchive扩展之前,需要确保已经安装了这个扩展。安装方法如下:1.安

php如何使用PHP的POSIX扩展?php如何使用PHP的POSIX扩展?Jun 03, 2023 am 08:01 AM

PHP的POSIX扩展是一组允许PHP与POSIX兼容操作系统进行交互的函数和常量。POSIX(PortableOperatingSystemInterface)是一组操作系统接口标准,旨在允许软件开发人员编写可在各种UNIX或UNIX类操作系统上运行的应用程序。本文将介绍如何使用PHP的POSIX扩展,包括安装和使用。一、安装PHP的POSIX扩展在

php如何使用PHP的Phar扩展?php如何使用PHP的Phar扩展?May 31, 2023 pm 11:31 PM

随着PHP的发展和应用场景的不断扩大,Phar扩展已经成为PHP编程中的重要一环。Phar是PHPArchive的缩写,它可以将多个PHP文件和资源打包成单个文件,方便进行分发和管理。本文将介绍如何使用PHP的Phar扩展来进行打包和管理。安装Phar扩展首先,我们需要检查PHP是否已经安装Phar扩展。在Linux下,通过终端输入以下命令:php-m

教程:使用百度云推送(Baidu Push)扩展在PHP应用中实现消息推送功能教程:使用百度云推送(Baidu Push)扩展在PHP应用中实现消息推送功能Jul 26, 2023 am 09:25 AM

教程:使用百度云推送(BaiduPush)扩展在PHP应用中实现消息推送功能引言:随着移动应用的迅猛发展,消息推送功能在应用程序中变得越来越重要。为了实现即时通知和消息推送功能,百度提供了一种强大的云推送服务,即百度云推送(BaiduPush)。在本教程中,我们将学习如何使用百度云推送扩展(PHPSDK)在PHP应用中实现消息推送功能。我们将使用百度云

PHP和WebDriver扩展:如何模拟用户点击和输入操作PHP和WebDriver扩展:如何模拟用户点击和输入操作Jul 07, 2023 pm 05:10 PM

PHP和WebDriver扩展:如何模拟用户点击和输入操作近年来,随着Web应用程序的快速发展,自动化测试变得越来越重要。在自动化测试中,模拟用户操作是一个关键的环节,它可以使我们更准确地测试和验证我们的应用程序。在PHP开发中,我们通常使用SeleniumWebDriver来实现自动化测试。SeleniumWebDriver是一种强大的工具,它可以模拟

Vue如何实现组件的复用和扩展?Vue如何实现组件的复用和扩展?Jun 27, 2023 am 10:22 AM

随着前端技术的不断发展,Vue已经成为了前端开发中的热门框架之一。在Vue中,组件是其中的核心概念之一,它可以将页面分解为更小,更易管理的部分,从而提高开发效率和代码复用性。本文将重点介绍Vue如何实现组件的复用和扩展。一、Vue组件复用mixinsmixins是Vue中的一种共享组件选项的方式。Mixins允许将多个组件的组件选项合并成一个对象,从而最大

See all articles

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

AI Hentai Generator

AI Hentai Generator

免费生成ai无尽的。

热门文章

R.E.P.O.能量晶体解释及其做什么(黄色晶体)
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳图形设置
3 周前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您听不到任何人,如何修复音频
3 周前By尊渡假赌尊渡假赌尊渡假赌

热工具

螳螂BT

螳螂BT

Mantis是一个易于部署的基于Web的缺陷跟踪工具,用于帮助产品缺陷跟踪。它需要PHP、MySQL和一个Web服务器。请查看我们的演示和托管服务。

SecLists

SecLists

SecLists是最终安全测试人员的伙伴。它是一个包含各种类型列表的集合,这些列表在安全评估过程中经常使用,都在一个地方。SecLists通过方便地提供安全测试人员可能需要的所有列表,帮助提高安全测试的效率和生产力。列表类型包括用户名、密码、URL、模糊测试有效载荷、敏感数据模式、Web shell等等。测试人员只需将此存储库拉到新的测试机上,他就可以访问到所需的每种类型的列表。

PhpStorm Mac 版本

PhpStorm Mac 版本

最新(2018.2.1 )专业的PHP集成开发工具

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境