[actual combat] how to quickly create dynamic web pages through HTML + CSS + MySQL + PHP (in the column of making a blog website)

mind_ programmonkey 2020-11-13 04:23:01
actual combat quickly create dynamic


   In these days of summer vacation , Made a simple blog site . Let me talk about the operation process of these days , Code will be posted at the end of the original text , There will also be a download link .( Idle copy code trouble can go to download address here directly download   Click to open the link ) Just updated the source code to github On Click to open the link

One 、 Build the development environment

   1)apache+php+mysql Environment building

   Because of the need to use apache To be a server ,mysql As a database to store data ,php To write code to realize the interactive data between web page and database , So you need to download the above software , But the installation environment of the above software 、 Configuration is a hassle , So here used a powerful station building integration software package ---XAMPP, See the link for specific installation methods ( Click to open the link ).

        

   Of course , It's also possible to start Apache There was a mistake , Here's a link ( Click to open the link ), If apache Please refer to the above link to solve the problem if there is an error in startup .

   2) Database client software navigat

   Directly in cmd The command console is not convenient to operate the database , Not straightforward enough , It can also be used directly phpmyadmin To operate ( Above xampp After the package is installed, type in the explorer 127.0.0.1/phpmyadmin You can open ), however phpmyadmin It's not convenient to operate , Here we use Oracle Database client produced by the company Navicat, Here's the link ( Click to open the link ), Download as required ,

        Click to connect , Enter the connection name ,( Here I take it directly IP The name of the address 127.0.0.1), The host name and port number do not need to be changed , Here's the username and password . If you use xampp, So the user name is root, The password is empty. ; If it's not for xampp Installed , Login according to the user name and password you set . Click Connect test after filling in , You can connect to the database without any problem .

                            

    Besides, if you want to master the database , In short, you want to do anything with the database , All must be operated sql sentence , Generally speaking, it is divided into four operations : Additions and deletions .

                  

    ① increase : Write data to the database

    sentence :insert into users (`username`,`password`) values ('name','passwd')

    (ps The novice must pay attention to this users At the back of this data sheet `` this individual The sign is in tab The quotation mark above the key , and values It's followed by a single quotation mark )

    ② Delete : Delete existing data

    sentence :delete from users WHERE id='3'

    ③ Change : Modifying data

    sentence :update set users username=' The new value ', password=' The new value ' WHERE id=3

    ④ check : Reading data from a database

    sentence :select * from users where id>1 order by id desc limit 0,2

    If you want to know more about mysql In words , Take a look at the connection here , Click to open the link The connection gives a detailed explanation of the specific parameters of these four operations , If you want to use a database, you must master these four operations .


   (3)html Web page writing tools sublime text

   Sublime Text It's a code editor (Sublime Text 2 It's charging software , But you can try it indefinitely ), It's also HTML And prose advanced text editor .Sublime text Beautiful user interface and powerful functions , Great for writing code . It's still given here sublime text Installation method and registration code and common plug-in installation steps , Download according to the connection .( Click to open the link

         

   use sublime text To write web code , You can master this little trick , First create a new file , Format saved as html Web format , And then in sublime text Open in , Input html:4s Then press tab Key to generate the general framework . Of course, if you want to use this shortcut key, you should follow the link given above , Follow the steps to install Emmet This plugin , Can be used .

  4) Configuration of website domain name

   In general , You turn it on in the explorer 127.0.0.1 This web site , Will turn to apache A URL in the default directory , I modify it here , Modify the directory for my project ,E:\PHP\xampp\apache\conf, open httpd.conf file , Change the path inside to the directory where you store the website , Here I change it to

    DocumentRoot "E:/php/xampp/workplace"
    <Directory "E:/PHP/xampp/workplace">

   this Pay attention to According to their own download, according to the path to modify their own directory , Secondly, I'm also concerned about this 127.0.0.1 This website has been modified again , Make its virtual domain name as blog.com, Specific configuration and modification or see the link Click to open the link ), After modification, after restart , Enter... In the navigator blog.com, The following scenario will appear :

       

   Here I find that I modified DNS To configure , I don't know when I added a note before , It's impossible to open , We should also pay attention to the connection configuration given by me , If you can't open it, check the configuration file for errors .

All in all , The configuration environment and tools are basically built successfully , I'm going to talk about this blog Project .

   Two 、 Blog site writing

   1. General framework

   First of all, let me introduce my overall framework , Explain , Let's get familiar with .

             

  blog It's the name of the project ,admin In the folder is the background login file  core The core files are stored in the folder ,theme Folders store style files for web pages  upfiles Folders are used to store image information uploaded locally to the server , after config.php The file is the configuration file for the entire blog site ,header.inc.php Is to load a page style information ,index.php The document is the homepage of the website ,read.php The document is a link to the article on the front page of the website .


   The design in the database table is given here , It's convenient for you to learn by reference , Here I have mainly set up three tables ,admin This represents the data used to store background administrator registration and login , Account and password :


    page This table is mainly used to store blog information , Here's also the picture , It's easy to set up a diagram to build a table :


   Finally gives setting This table , It is mainly used to store the system settings of blog :

            

  2. Website backstage admin Writing

 1) Login screen (login.php)



   About this page, I will give the source code here , The login page is actually a process of reading from the database , The design of this login page is mainly based on bootstrap To design the , Don't understand can baidu bootstrap, You can refer to my link to see ( Click to open the link


   In this, it contains all kinds of styles 、 Components and JavaScript plug-in unit , It's easy to use .

        

   My way of using it here is to bootstrap download , And then pressurize the document , Copied to the theme Under this folder , Call method see the following source code , In the source code, I have given a detailed explanation .

   Source code :

  

<?php
/*
Background administrator login window
*/
/* start-up session service , Record account login cookies*/
session_start();
/* Contains a configuration file */
include('../config.php');
if($input->get('do')=='check'){
/* Get the user name and password data submitted by the page */
$ausername=$input->post('ausername');
$apassword=$input->post('apassword');
/* Query whether the data submitted by the page exists in the data provided by the database sql sentence */
$sql="select * from admin where ausername='{$ausername}' and apassword='{$apassword}' ";
/* The database query statement returns the result */
$mysqli_result=$db->query($sql);
/* Store the returned result of database query statement in the form of array */
$row=$mysqli_result->fetch_array( MYSQLI_ASSOC);
/* If row It did return the result , Then the result will be aid Stored in session in , And turn to home.php file */
if(is_array($row)){
$_SESSION['aid']=$row['aid'];
header("location:home.php");
}else{
echo(" Wrong account or password ");
}
}
?>
<!-- Background administrator login interface ></!-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title> Administrator login interface </title>
<!-- Load contains bootstrap in css and javascript Files in ></!-->
<?php include(PATH . '/header.inc.php');?>
</head>
<body>
<!-- The outermost container Containers ></!-->
<div class="container">
<!--bootstrap It is recommended to use a row Form class , contain 12 Columns ></!-->
<div class="row" style="margin-top:200px;">
<!-- To the left 3 Columns ></!-->
<div class="col-md-3"></div>
<!-- The middle part occupies 6 Column ></!-->
<div class="col-md-6" ">
<div class="panel panel-primary">
<!-- Login header section ></!-->
<div class="panel-heading"> Administrator login </div>
<!-- The body part of the login ></!-->
<div class="panel-body">
<form class="form-horizontal" action="login.php?do=check" method="post">
<!-- Login user name line ></!-->
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label"> user name </label>
<div class="col-sm-10">
<input type="text" class="form-control" name="ausername" id="ausername" placeholder=" Please enter a user name " datatype="*3-10" errormsg=" Please enter the length The scope is 3-10 Between the nicknames ">
</div>
</div>
<!-- The login password line ></!-->
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label"> password </label>
<div class="col-sm-10">
<input type="password" class="form-control" name="apassword" id="apassword" placeholder=" Please input a password ">
</div>
</div>
<!-- Sign in 、 The registration line ></!-->
<div class="form-group">
<div class="col-sm-3"></div>
<!-- Sign in ></!-->
<div class="col-sm-4">
<input type="submit" value=" Sign in " class='btn btn-primary'>
</div>
<!-- register ></!-->
<div class="col-sm-4">
<a href="register.php"><input type="button" value=" register " class="btn btn-primary"> </a>
</div>
</div>
</form>
</div>
<!-- The end of the login ></!-->
<div class="panel-footer text-right"> copyright , Piracy must be investigated </div>
</div>
</div>
<!-- Three columns to the right ></!-->
<div class="col-md-3"></div>
</div>
</div>
<!-- Window background script load ></!-->
<script type="text/javascript">
window.onload = function() {
var config = {
vx : 4,
vy : 4,
height : 2,
width : 2,
count : 100,
color : "121, 162, 185",
stroke : "100, 200, 180",
dist : 6000,
e_dist : 20000,
max_conn : 10
}
CanvasParticle(config);
}
</script>
<script type="text/javascript" src="../theme/js/canvas-particle.js"></script>
</script>
</body>
</html>

   (2) The registration screen (register.php)

   The registration interface is actually a process of adding data to the database .

  

   Or give the source code , In the source code, I gave a detailed explanation .

  

<?php
/* Contains a configuration file */
include('../config.php');
if($input->get('do')=='check'){
/* Get user name and password data from user page registration */
$ausername=$input->post('ausername');
$apassword=$input->post('apassword');
$aconfirmpassword=$input->post('aconfirmpassword');
/* Registration processing */
if($apassword!=$aconfirmpassword){
echo " The passwords entered before and after do not match ";
exit;
}
/* Insert the data filled by the user into the database sql sentence */
$sql="INSERT INTO admin(`ausername`,`apassword`) values('$ausername','$apassword')";
/* Submit sql Statement to the database processing */
$is=$db->query($sql);
/* Judge whether the registration is successful */
if($is){
echo " Registered successfully ";
header("Location:login.php");
}else{
echo " Registration failed ";
}
}
?>
<!-- Background administrator login interface ></!-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title> Administrator registration interface </title>
<!-- Load contains bootstrap in css and javascript Files in ></!-->
<?php include(PATH . '/header.inc.php');?>
</head>
<body>
<!-- The outermost container Containers ></!-->
<div class="container">
<!--bootstrap It is recommended to use a row Form class , contain 12 Columns ></!-->
<div class="row" style="margin-top:200px;">
<!-- To the left 3 Columns ></!-->
<div class="col-md-3"></div>
<!-- The middle part occupies 6 Column ></!-->
<div class="col-md-6" ">
<div class="panel panel-primary">
<!-- Registration header ></!-->
<div class="panel-heading"> Administrator registration </div>
<!-- Registered body parts ></!-->
<div class="panel-body">
<form class="form-horizontal" action="register.php?do=check" method="post">
<!-- The line of registered user name ></!-->
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label"> user name </label>
<div class="col-sm-10">
<input type="text" class="form-control" name="ausername" id="ausername" placeholder=" Please enter a user name ">
</div>
</div>
<!-- The password line of registration ></!-->
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label"> password </label>
<div class="col-sm-10">
<input type="password" class="form-control" name="apassword" id="apassword" placeholder=" Please input a password ">
</div>
</div>
<!-- The registered password determines which line ></!-->
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label"> Confirm the password </label>
<div class="col-sm-10">
<input type="password" class="form-control" name="aconfirmpassword" id="aconfirmpassword" placeholder=" Please input the password again ">
</div>
</div>
<!-- The line of filing for registration ></!-->
<div class="form-group">
<div class="col-sm-4"></div>
<div class="col-sm-6">
<input type="submit" value=" register " class='btn btn-primary btn-lg btn-block'>
</div>
</div>
</form>
</div>
<!-- The end of the login ></!-->
<div class="panel-footer text-right"> copyright , Piracy must be investigated </div>
</div>
</div>
<!-- Three columns to the right ></!-->
<div class="col-md-3"></div>
</div>
</div>
<!-- Window background script load ></!-->
<script type="text/javascript">
window.onload = function() {
var config = {
vx : 4,
vy : 4,
height : 2,
width : 2,
count : 100,
color : "121, 162, 185",
stroke : "100, 200, 180",
dist : 6000,
e_dist : 20000,
max_conn : 10
}
CanvasParticle(config);
}
</script>
<script type="text/javascript" src="../theme/js/canvas-particle.js"></script>
</script>
</body>
</html>

   3) Background management page (home.php)



  In the source code will be the title of the site that part of the separate to do a file (nav.inc.php, Here is the source code , For your reference .

 home.php Source code

<?php
/*
After the background administrator logs in php Control terminal
*/
include ('check.php');
?>
<!-- Background administrator login after the interface <>/!-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title> Administrator login </title>
<?php include(PATH . '/header.inc.php');?> <!-- All pages need to load this file ></!-->
</head>
<body>
<?php include('nav.inc.php');?> <!-- The title section of the administrator login page ></!-->
</body>
</html>
 nav.inc.php

 

<!-- The top title of the background management interface ></!-->
<nav class="navbar navbar-default" role="navigation">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="home.php">ADMIN</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li ><a href="blog.php"> Blog management <span class="sr-only">(current)</span></a></li>
<li><a href="auser.php"> Administrator management </a></li>
<li><a href="setting.php"> System management </a></li>
</ul>
<ul class="nav navbar-nav navbar-right">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false"> <?php echo $session_user['ausername'];?> <span class="caret"></span></a> <!-- Output the login account name at this time ></!-->
<ul class="dropdown-menu">
<li><a href="logout.php"> sign out </a></li>
</ul>
</li>
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav> 

  4) Blog management interface (blog.php

  There are three functions here , modify 、 Delete 、 Add a blog interface , I'll list the add blog interface separately




  (5) Add a blog interface (blog_add.php)

   Why list the add blog interface separately ? Because an editor is loaded in the add blog interface , A powerful online editor simditor, Here's still a link to download and use , You can use it as a reference , To learn Click to open the link Here, if the editor needs image upload function , Set in file , This file is set to (blog_uopload.php)

   blog_add.php Source code

 

<?php
/* Remove the administrator login interface from the background , You need to load this file , To verify that the page administrator is logged in */
include ('check.php');
/* Take out what's coming pid To determine whether to add or modify operations */
$pid=$input->get('pid');
/* initialization page, To distinguish between adding and modifying operations */
$page=array(
'title' => '',
'author' => '',
'content' => '',
);
/* If pid Greater than 0, It's not an add operation , It's a modification operation */
if($pid>0){
$sql="select * from page where pid ='{$pid}' ";
$res=$db->query($sql);
$page=$res->fetch_array(MYSQLI_ASSOC);
}
/* For addition operations , Account or password cannot be empty */
if($input->get('do')=='add'){
$title=$input->post('title');
$author=$input->post('author');
$content=$input->post('content');
if(empty($title)||empty($author)||empty($content)){
echo(" Data cannot be empty ");
}
/* If aid Greater than 1, Then we get the update operation , Otherwise, perform the add operation */
if($pid>0){
$uptime=time();
$sqlTpl="UPDATE page set title='%s',author='%s',content='%s',uptime='%d' where pid='%d' ";
$sql=sprintf($sqlTpl,$title,$author,$content,$uptime,$pid);
}
else{
$intime=time();
$sqlTpl="INSERT INTO page(`title`,`author`,`content`,`intime`,`uptime`) values('%s','%s','%s','%d','%d')";
$sql=sprintf($sqlTpl,$title,$author,$content,$intime,0);
}
/* Judge whether there is a result */
$is=$db->query($sql);
if($is){
header("location:blog.php");
}else{
echo " Execution failure ";
}
}
?>
<!-- The interface for administrators to add or modify blogs <>/!-->
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<title> Add a blog </title>
<?php include(PATH . '/header.inc.php');?>
<!-- load simiditor Editor's file ></!-->
<link rel="stylesheet" type="text/css" href="../theme/simditor/styles/simditor.css" />
<script type="text/javascript" src="../theme/simditor/scripts/module.js"></script>
<script type="text/javascript" src="../theme/simditor/scripts/hotkeys.js"></script>
<script type="text/javascript" src="../theme/simditor/scripts/uploader.js"></script>
<script type="text/javascript" src="../theme/simditor/scripts/simditor.js"></script>
</head>
<body>
<?php include('nav.inc.php');?>
<div class="container">
<h2> Blog management <small class="pull-right"><a class='btn btn-default' href="blog.php"> return </a></small></h2>
<hr/>
<div class="rows">
<form class="form-horizontal" role="form" action="blog_add.php?do=add&pid=<?php echo $pid;?>" method="post">
<div class="form-group">
<label for="inputEmail3" class="col-sm-2 control-label"> title </label>
<div class="col-sm-6">
<input type="text" class="form-control" name="title" placeholder=" Please enter a title " value='<?php echo $page['title'];?>'>
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label"> author </label>
<div class="col-sm-4">
<input type="text" class="form-control" name="author" placeholder=" Please enter the author " value='<?php echo $page['author'];?>' >
</div>
</div>
<div class="form-group">
<label for="inputPassword3" class="col-sm-2 control-label"> Text </label>
<div class="col-sm-8">
<textarea id="content" name="content" class="form-control"><?php echo $page['content'];?></textarea>
<!-- stay script Initialize editor in , Pay attention to script It's loaded with textarea Of ID With the top textarea Of id No ></!-->
<script>
var editor = new Simditor({
textarea: $('#content'),
upload:{
url:'blog_upload.php',
fileKey:'file1'
}
//optional options
});
</script>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-6">
<button type="submit" class="btn btn-default"> Submit </button>
</div>
</div>
</form>
</div>
</div>
</body>
</html>
 
  

  blog_upload.php Source code

 

<?php
/* Remove the administrator login interface from the background , You need to load this file , To verify that the page administrator is logged in */
include('check.php');
/* Upload the file to the server directory */
$key='file1';
$dir='../upfiles/';
if(isset($_FILES[$key])){
$file=$_FILES[$key];
if($file['error']==0){
/* The directory of the server where the file is located */
$pathName=$dir . $file['name'];
/* The web address of the server where the file is located */
$urlName='http://blog.com/blog/upfiles' . $file['name'];
$is=move_uploaded_file($file['tmp_name'], $pathName);
/* Judge whether the move is successful */
if(!$is){
die(" Upload failed ");
}
/* Editor to determine whether the image was successfully uploaded */
$json=array(
'success' => true,
'msg' => '',
'file_path'=>$urlName
);
echo json_encode($json);
}
}
?>

  6) Administrator management interface (auser.php)

  There are still three functions here , modify 、 Delete and add , I will not list them separately here , Please refer to the source code at the end of the paper

 

  7) System management interface

  System management can set the title here 、 Number of presentations and blogs displayed per page

 




  3. main interface index.php)

  This is the main interface for tourists to visit , Here we give the source code as a reference ,

 

  Read the interface (read.php)

  When you want to read the article , Click on the title to enter the reading page , To read , Also give the source code , As a reference





版权声明
本文为[mind_ programmonkey]所创,转载请带上原文链接,感谢

  1. [front end -- JavaScript] knowledge point (IV) -- memory leakage in the project (I)
  2. This mechanism in JS
  3. Vue 3.0 source code learning 1 --- rendering process of components
  4. Learning the realization of canvas and simple drawing
  5. gin里获取http请求过来的参数
  6. vue3的新特性
  7. Get the parameters from HTTP request in gin
  8. New features of vue3
  9. vue-cli 引入腾讯地图(最新 api,rocketmq原理面试
  10. Vue 学习笔记(3,免费Java高级工程师学习资源
  11. Vue 学习笔记(2,Java编程视频教程
  12. Vue cli introduces Tencent maps (the latest API, rocketmq)
  13. Vue learning notes (3, free Java senior engineer learning resources)
  14. Vue learning notes (2, Java programming video tutorial)
  15. 【Vue】—props属性
  16. 【Vue】—创建组件
  17. [Vue] - props attribute
  18. [Vue] - create component
  19. 浅谈vue响应式原理及发布订阅模式和观察者模式
  20. On Vue responsive principle, publish subscribe mode and observer mode
  21. 浅谈vue响应式原理及发布订阅模式和观察者模式
  22. On Vue responsive principle, publish subscribe mode and observer mode
  23. Xiaobai can understand it. It only takes 4 steps to solve the problem of Vue keep alive cache component
  24. Publish, subscribe and observer of design patterns
  25. Summary of common content added in ES6 + (II)
  26. No.8 Vue element admin learning (III) vuex learning and login method analysis
  27. Write a mini webpack project construction tool
  28. Shopping cart (front-end static page preparation)
  29. Introduction to the fluent platform
  30. Webpack5 cache
  31. The difference between drop-down box select option and datalist
  32. CSS review (III)
  33. Node.js学习笔记【七】
  34. Node.js learning notes [VII]
  35. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  36. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  37. 【JQuery框架,Java编程教程视频下载
  38. [jQuery framework, Java programming tutorial video download
  39. Vue Router根据后台数据加载不同的组件(思考-&gt;实现-&gt;不止于实现)
  40. Vue router loads different components according to background data (thinking - & gt; Implementation - & gt; (more than implementation)
  41. 【Vue,阿里P8大佬亲自教你
  42. 【Vue基础知识总结 5,字节跳动算法工程师面试经验
  43. [Vue, Ali P8 teaches you personally
  44. [Vue basic knowledge summary 5. Interview experience of byte beating Algorithm Engineer
  45. 【问题记录】- 谷歌浏览器 Html生成PDF
  46. [problem record] - PDF generated by Google browser HTML
  47. 【问题记录】- 谷歌浏览器 Html生成PDF
  48. [problem record] - PDF generated by Google browser HTML
  49. 【JavaScript】查漏补缺 —数组中reduce()方法
  50. [JavaScript] leak checking and defect filling - reduce() method in array
  51. 【重识 HTML (3),350道Java面试真题分享
  52. 【重识 HTML (2),Java并发编程必会的多线程你竟然还不会
  53. 【重识 HTML (1),二本Java小菜鸟4面字节跳动被秒成渣渣
  54. [re recognize HTML (3) and share 350 real Java interview questions
  55. [re recognize HTML (2). Multithreading is a must for Java Concurrent Programming. How dare you not
  56. [re recognize HTML (1), two Java rookies' 4-sided bytes beat and become slag in seconds
  57. 【重识 HTML ,nginx面试题阿里
  58. 【重识 HTML (4),ELK原来这么简单
  59. [re recognize HTML, nginx interview questions]
  60. [re recognize HTML (4). Elk is so simple