Skip to content

Commit 81cbe43

Browse files
committed
2 parents aeb02df + a828d5c commit 81cbe43

File tree

5 files changed

+519
-9
lines changed

5 files changed

+519
-9
lines changed

api.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,7 +1102,7 @@ protected function exitWith422($object) {
11021102

11031103
protected function headersCommand($parameters) {
11041104
$headers = array();
1105-
$headers[]='Access-Control-Allow-Headers: Content-Type';
1105+
$headers[]='Access-Control-Allow-Headers: Content-Type, X-XSRF-Token';
11061106
$headers[]='Access-Control-Allow-Methods: OPTIONS, GET, PUT, POST, DELETE, PATCH';
11071107
$headers[]='Access-Control-Allow-Credentials: true';
11081108
$headers[]='Access-Control-Max-Age: 1728000';
@@ -2367,7 +2367,7 @@ public function executeCommand() {
23672367
// 'secret'=>'someVeryLongPassPhraseChangeMe',
23682368
// ));
23692369
// if ($auth->executeCommand()) exit(0);
2370-
// if (empty($_SESSION['user']) || $_GET['csrf']!=$_SESSION['csrf']) {
2370+
// if (empty($_SESSION['user']) || !$auth->hasValidCsrfToken()) {
23712371
// header('HTTP/1.0 401 Unauthorized');
23722372
// exit(0);
23732373
// }
@@ -2378,7 +2378,7 @@ public function executeCommand() {
23782378
// 'authenticator'=>function($user,$pass){ $_SESSION['user']=($user=='admin' && $pass=='admin'); }
23792379
// ));
23802380
// if ($auth->executeCommand()) exit(0);
2381-
// if (empty($_SESSION['user']) || $_GET['csrf']!=$_SESSION['csrf']) {
2381+
// if (empty($_SESSION['user']) || !$auth->hasValidCsrfToken()) {
23822382
// header('HTTP/1.0 401 Unauthorized');
23832383
// exit(0);
23842384
// }

examples/client_angular2_auth.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
};
2424
var url = "../api.php";
2525
http.post(url,JSON.stringify({username:"admin",password:"admin"})).subscribe(res => {
26-
url += "/posts?csrf="+res._body;
26+
url += "/posts?csrf="+JSON.parse(res._body);
2727
http.post(url,JSON.stringify({user_id:1,category_id:1,content:"from angular2"})).subscribe();
2828
http.get(url).map(res => php_crud_api_transform(res.json())).subscribe(res => this.posts = res.posts);
2929
});

examples/client_auth.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,21 @@
33

44
$cookiejar = tempnam(sys_get_temp_dir(), 'cookiejar-');
55

6-
function call($method, $url, $data = false) {
6+
function call($method, $url, $data = false, $csrf = false) {
77
global $cookiejar;
88
$ch = curl_init();
99
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
1010
curl_setopt($ch, CURLOPT_URL, $url);
11+
$headers = array();
1112
if ($data) {
1213
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
13-
$headers = array();
1414
$headers[] = 'Content-Type: application/json';
1515
$headers[] = 'Content-Length: ' . strlen($data);
16-
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
1716
}
17+
if ($csrf) {
18+
$headers[] = 'X-XSRF-TOKEN: ' . $csrf;
19+
}
20+
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
1821
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
1922

2023
curl_setopt($ch, CURLOPT_COOKIEJAR, $cookiejar);
@@ -24,8 +27,8 @@ function call($method, $url, $data = false) {
2427
}
2528

2629
// in case you are using php-api-auth:
27-
$csrf = call('POST','http://localhost/blog.php/', 'username=admin&password=admin');
28-
$response = call('GET','http://localhost/blog.php/posts?include=categories,tags,comments&filter=id,eq,1&csrf='. trim($csrf));
30+
$csrf = json_decode(call('POST','http://localhost/api.php/', 'username=admin&password=admin'));
31+
$response = call('GET','http://localhost/api.php/posts?include=categories,tags,comments&filter=id,eq,1', false, $csrf);
2932

3033
unlink($cookiejar);
3134

examples/client_vue.html

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
<html lang="en">
2+
<head>
3+
<meta charset="utf-8">
4+
<meta http-equiv="x-ua-compatible" content="ie=edge">
5+
<title>Vue.js CRUD application</title>
6+
<meta name="description" content="">
7+
<meta name="viewport" content="width=device-width, initial-scale=1">
8+
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.1.10/vue.js"></script>
9+
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue-router/2.2.1/vue-router.js"></script>
10+
<script src="https://cdnjs.cloudflare.com/ajax/libs/axios/0.15.3/axios.js"></script>
11+
<script src="../lib/php_crud_api_transform.js"></script>
12+
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css">
13+
<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap-theme.min.css">
14+
<style>
15+
.logo {
16+
width: 50px;
17+
float: left;
18+
margin-right: 15px;
19+
}
20+
21+
.form-group {
22+
max-width: 500px;
23+
}
24+
25+
.actions {
26+
padding: 10px 0;
27+
}
28+
29+
.glyphicon-euro {
30+
font-size: 12px;
31+
}
32+
</style>
33+
</head>
34+
<body>
35+
36+
<div class="container">
37+
<header class="page-header">
38+
<div class="branding">
39+
<img src="https://vuejs.org/images/logo.png" alt="Logo" title="Home page" class="logo"/>
40+
<h1>Vue.js CRUD application</h1>
41+
</div>
42+
</header>
43+
<main id="app">
44+
<router-view></router-view>
45+
</main>
46+
</div>
47+
48+
<template id="post-list">
49+
<div>
50+
<div class="actions">
51+
<router-link class="btn btn-default" v-bind:to="{path: '/add-post'}">
52+
<span class="glyphicon glyphicon-plus"></span>
53+
Add post
54+
</router-link>
55+
</div>
56+
<div class="filters row">
57+
<div class="form-group col-sm-3">
58+
<label for="search-element">Filter</label>
59+
<input v-model="searchKey" class="form-control" id="search-element" requred/>
60+
</div>
61+
</div>
62+
<table class="table">
63+
<thead>
64+
<tr>
65+
<th>Content</th>
66+
<th class="col-sm-2">Actions</th>
67+
</tr>
68+
</thead>
69+
<tbody>
70+
<tr v-if="posts===null">
71+
<td colspan="4">Loading...</td>
72+
</tr>
73+
<tr v-else v-for="post in filteredposts">
74+
<td>
75+
<router-link v-bind:to="{name: 'post', params: {post_id: post.id}}">{{ post.content }}</router-link>
76+
</td>
77+
<td>
78+
<router-link class="btn btn-warning btn-xs" v-bind:to="{name: 'post-edit', params: {post_id: post.id}}">Edit</router-link>
79+
<router-link class="btn btn-danger btn-xs" v-bind:to="{name: 'post-delete', params: {post_id: post.id}}">Delete</router-link>
80+
</td>
81+
</tr>
82+
</tbody>
83+
</table>
84+
</div>
85+
</template>
86+
87+
<template id="add-post">
88+
<div>
89+
<h2>Add new post</h2>
90+
<form v-on:submit="createpost">
91+
<div class="form-group">
92+
<label for="add-content">Content</label>
93+
<textarea class="form-control" id="add-content" rows="10" v-model="post.content"></textarea>
94+
</div>
95+
<button type="submit" class="btn btn-primary">Create</button>
96+
<router-link class="btn btn-default" v-bind:to="'/'">Cancel</router-link>
97+
</form>
98+
</div>
99+
</template>
100+
101+
<template id="post">
102+
<div>
103+
<b>Content: </b>
104+
<div>{{ post.content }}</div>
105+
<br/>
106+
<span class="glyphicon glyphicon-arrow-left" aria-hidden="true"></span>
107+
<router-link v-bind:to="'/'">Back to post list</router-link>
108+
</div>
109+
</template>
110+
111+
<template id="post-edit">
112+
<div>
113+
<h2>Edit post</h2>
114+
<form v-on:submit="updatepost">
115+
<div class="form-group">
116+
<label for="edit-content">Content</label>
117+
<textarea class="form-control" id="edit-content" rows="3" v-model="post.content"></textarea>
118+
</div>
119+
<button type="submit" class="btn btn-primary">Save</button>
120+
<router-link class="btn btn-default" v-bind:to="'/'">Cancel</router-link>
121+
</form>
122+
</div>
123+
</template>
124+
125+
<template id="post-delete">
126+
<div>
127+
<h2>Delete post {{ post.id }}</h2>
128+
<form v-on:submit="deletepost">
129+
<p>The action cannot be undone.</p>
130+
<button type="submit" class="btn btn-danger">Delete</button>
131+
<router-link class="btn btn-default" v-bind:to="'/'">Cancel</router-link>
132+
</form>
133+
</div>
134+
</template>
135+
136+
<script>
137+
var posts = null;
138+
139+
var api = axios.create({
140+
baseURL: '../api.php'
141+
});
142+
143+
function findpost (postId) {
144+
return posts[findpostKey(postId)];
145+
};
146+
147+
function findpostKey (postId) {
148+
for (var key = 0; key < posts.length; key++) {
149+
if (posts[key].id == postId) {
150+
return key;
151+
}
152+
}
153+
};
154+
155+
var List = Vue.extend({
156+
template: '#post-list',
157+
data: function () {
158+
return {posts: posts, searchKey: ''};
159+
},
160+
created: function () {
161+
var self = this;
162+
api.get('/posts').then(function (response) {
163+
posts = self.posts = php_crud_api_transform(response.data).posts;
164+
}).catch(function (error) {
165+
console.log(error);
166+
});
167+
},
168+
computed: {
169+
filteredposts: function () {
170+
return this.posts.filter(function (post) {
171+
return this.searchKey=='' || post.content.indexOf(this.searchKey) !== -1;
172+
},this);
173+
}
174+
}
175+
});
176+
177+
var post = Vue.extend({
178+
template: '#post',
179+
data: function () {
180+
return {post: findpost(this.$route.params.post_id)};
181+
}
182+
});
183+
184+
var postEdit = Vue.extend({
185+
template: '#post-edit',
186+
data: function () {
187+
return {post: findpost(this.$route.params.post_id)};
188+
},
189+
methods: {
190+
updatepost: function () {
191+
var post = this.post;
192+
api.put('/posts/'+post.id,post).then(function (response) {
193+
console.log(response.data);
194+
}).catch(function (error) {
195+
console.log(error);
196+
});
197+
router.push('/');
198+
}
199+
}
200+
});
201+
202+
var postDelete = Vue.extend({
203+
template: '#post-delete',
204+
data: function () {
205+
return {post: findpost(this.$route.params.post_id)};
206+
},
207+
methods: {
208+
deletepost: function () {
209+
var post = this.post;
210+
api.delete('/posts/'+post.id).then(function (response) {
211+
console.log(response.data);
212+
}).catch(function (error) {
213+
console.log(error);
214+
});
215+
router.push('/');
216+
}
217+
}
218+
});
219+
220+
var Addpost = Vue.extend({
221+
template: '#add-post',
222+
data: function () {
223+
return {post: {content: '', user_id: 1, category_id: 1}}
224+
},
225+
methods: {
226+
createpost: function() {
227+
var post = this.post;
228+
api.post('/posts',post).then(function (response) {
229+
post.id = response.data;
230+
}).catch(function (error) {
231+
console.log(error);
232+
});
233+
router.push('/');
234+
}
235+
}
236+
});
237+
238+
var router = new VueRouter({routes:[
239+
{ path: '/', component: List},
240+
{ path: '/post/:post_id', component: post, name: 'post'},
241+
{ path: '/add-post', component: Addpost},
242+
{ path: '/post/:post_id/edit', component: postEdit, name: 'post-edit'},
243+
{ path: '/post/:post_id/delete', component: postDelete, name: 'post-delete'}
244+
]});
245+
app = new Vue({
246+
router:router
247+
}).$mount('#app')
248+
</script>
249+
250+
</body>
251+
</html>

0 commit comments

Comments
 (0)