├── README.md ├── chat.php ├── header.php ├── index.php ├── javascript ├── chat.js ├── login.js ├── pass-show-hide.js ├── signup.js └── users.js ├── login.php ├── php ├── config.php ├── data.php ├── get-chat.php ├── images │ ├── 1652660564avatar.png │ ├── 1652660638staff-avatar.png │ └── 1652670758chatbot.png ├── insert-chat.php ├── login.php ├── logout.php ├── search.php ├── signup.php └── users.php ├── style.css ├── unzipper.php └── users.php /README.md: -------------------------------------------------------------------------------- 1 | # Sistema de Chat en Línea en PHP y MySQL 2 | 3 | Este Sistema de Chat en Línea en PHP y MySQL con Código Fuente le permite al usuario registrarse y comunicarse con los usuarios que están conectados, la gran diferencia entre los chats anteriores es que este cambia en tiempo real, gracias a la tecnología de Ajax, solo recarga el div donde se encuentra el chat especifico y esto que la conversación por el chat sea más fluida. 4 | 5 | Más información en el siguiente enlace: Sistema de Chat en Línea en PHP y MySQL 6 | -------------------------------------------------------------------------------- /chat.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 |
12 |
13 |
14 | 0) { 18 | $row = mysqli_fetch_assoc($sql); 19 | } else { 20 | header("location: users.php"); 21 | } 22 | ?> 23 | 24 | 25 |
26 | 27 |

28 |
29 |
30 |
31 | 32 |
33 |
34 | 35 | 36 | 37 |
38 |
39 |
40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /header.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Sistema de Chat en Línea en PHP y MySQL 10 | 11 | 12 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
Sistema de Chat en Línea en PHP y MySQL
14 |
15 |
16 |
17 |
18 | 19 | 20 |
21 |
22 | 23 | 24 |
25 |
26 |
27 | 28 | 29 |
30 |
31 | 32 | 33 | 34 |
35 |
36 | 37 | 38 |
39 |
40 | 41 |
42 |
43 | 44 |
45 |
46 | 47 | 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /javascript/chat.js: -------------------------------------------------------------------------------- 1 | const form = document.querySelector(".typing-area"), 2 | incoming_id = form.querySelector(".incoming_id").value, 3 | inputField = form.querySelector(".input-field"), 4 | sendBtn = form.querySelector("button"), 5 | chatBox = document.querySelector(".chat-box"); 6 | 7 | form.onsubmit = (e)=>{ 8 | e.preventDefault(); 9 | } 10 | 11 | inputField.focus(); 12 | inputField.onkeyup = ()=>{ 13 | if(inputField.value != ""){ 14 | sendBtn.classList.add("active"); 15 | }else{ 16 | sendBtn.classList.remove("active"); 17 | } 18 | } 19 | 20 | sendBtn.onclick = ()=>{ 21 | let xhr = new XMLHttpRequest(); 22 | xhr.open("POST", "php/insert-chat.php", true); 23 | xhr.onload = ()=>{ 24 | if(xhr.readyState === XMLHttpRequest.DONE){ 25 | if(xhr.status === 200){ 26 | inputField.value = ""; 27 | scrollToBottom(); 28 | } 29 | } 30 | } 31 | let formData = new FormData(form); 32 | xhr.send(formData); 33 | } 34 | chatBox.onmouseenter = ()=>{ 35 | chatBox.classList.add("active"); 36 | } 37 | 38 | chatBox.onmouseleave = ()=>{ 39 | chatBox.classList.remove("active"); 40 | } 41 | 42 | setInterval(() =>{ 43 | let xhr = new XMLHttpRequest(); 44 | xhr.open("POST", "php/get-chat.php", true); 45 | xhr.onload = ()=>{ 46 | if(xhr.readyState === XMLHttpRequest.DONE){ 47 | if(xhr.status === 200){ 48 | let data = xhr.response; 49 | chatBox.innerHTML = data; 50 | if(!chatBox.classList.contains("active")){ 51 | scrollToBottom(); 52 | } 53 | } 54 | } 55 | } 56 | xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 57 | xhr.send("incoming_id="+incoming_id); 58 | }, 500); 59 | 60 | function scrollToBottom(){ 61 | chatBox.scrollTop = chatBox.scrollHeight; 62 | } 63 | -------------------------------------------------------------------------------- /javascript/login.js: -------------------------------------------------------------------------------- 1 | const form = document.querySelector(".login form"), 2 | continueBtn = form.querySelector(".button input"), 3 | errorText = form.querySelector(".error-text"); 4 | 5 | form.onsubmit = (e)=>{ 6 | e.preventDefault(); 7 | } 8 | 9 | continueBtn.onclick = ()=>{ 10 | let xhr = new XMLHttpRequest(); 11 | xhr.open("POST", "php/login.php", true); 12 | xhr.onload = ()=>{ 13 | if(xhr.readyState === XMLHttpRequest.DONE){ 14 | if(xhr.status === 200){ 15 | let data = xhr.response; 16 | if(data === "success"){ 17 | location.href = "users.php"; 18 | }else{ 19 | errorText.style.display = "block"; 20 | errorText.textContent = data; 21 | } 22 | } 23 | } 24 | } 25 | let formData = new FormData(form); 26 | xhr.send(formData); 27 | } -------------------------------------------------------------------------------- /javascript/pass-show-hide.js: -------------------------------------------------------------------------------- 1 | const pswrdField = document.querySelector(".form input[type='password']"), 2 | toggleIcon = document.querySelector(".form .field i"); 3 | 4 | toggleIcon.onclick = () =>{ 5 | if(pswrdField.type === "password"){ 6 | pswrdField.type = "text"; 7 | toggleIcon.classList.add("active"); 8 | }else{ 9 | pswrdField.type = "password"; 10 | toggleIcon.classList.remove("active"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /javascript/signup.js: -------------------------------------------------------------------------------- 1 | const form = document.querySelector(".signup form"), 2 | continueBtn = form.querySelector(".button input"), 3 | errorText = form.querySelector(".error-text"); 4 | 5 | form.onsubmit = (e)=>{ 6 | e.preventDefault(); 7 | } 8 | 9 | continueBtn.onclick = ()=>{ 10 | let xhr = new XMLHttpRequest(); 11 | xhr.open("POST", "php/signup.php", true); 12 | xhr.onload = ()=>{ 13 | if(xhr.readyState === XMLHttpRequest.DONE){ 14 | if(xhr.status === 200){ 15 | let data = xhr.response; 16 | if(data === "success"){ 17 | location.href="users.php"; 18 | }else{ 19 | errorText.style.display = "block"; 20 | errorText.textContent = data; 21 | } 22 | } 23 | } 24 | } 25 | let formData = new FormData(form); 26 | xhr.send(formData); 27 | } -------------------------------------------------------------------------------- /javascript/users.js: -------------------------------------------------------------------------------- 1 | const searchBar = document.querySelector(".search input"), 2 | searchIcon = document.querySelector(".search button"), 3 | usersList = document.querySelector(".users-list"); 4 | 5 | searchIcon.onclick = ()=>{ 6 | searchBar.classList.toggle("show"); 7 | searchIcon.classList.toggle("active"); 8 | searchBar.focus(); 9 | if(searchBar.classList.contains("active")){ 10 | searchBar.value = ""; 11 | searchBar.classList.remove("active"); 12 | } 13 | } 14 | 15 | searchBar.onkeyup = ()=>{ 16 | let searchTerm = searchBar.value; 17 | if(searchTerm != ""){ 18 | searchBar.classList.add("active"); 19 | }else{ 20 | searchBar.classList.remove("active"); 21 | } 22 | let xhr = new XMLHttpRequest(); 23 | xhr.open("POST", "php/search.php", true); 24 | xhr.onload = ()=>{ 25 | if(xhr.readyState === XMLHttpRequest.DONE){ 26 | if(xhr.status === 200){ 27 | let data = xhr.response; 28 | usersList.innerHTML = data; 29 | } 30 | } 31 | } 32 | xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); 33 | xhr.send("searchTerm=" + searchTerm); 34 | } 35 | 36 | setInterval(() =>{ 37 | let xhr = new XMLHttpRequest(); 38 | xhr.open("GET", "php/users.php", true); 39 | xhr.onload = ()=>{ 40 | if(xhr.readyState === XMLHttpRequest.DONE){ 41 | if(xhr.status === 200){ 42 | let data = xhr.response; 43 | if(!searchBar.classList.contains("active")){ 44 | usersList.innerHTML = data; 45 | } 46 | } 47 | } 48 | } 49 | xhr.send(); 50 | }, 500); 51 | 52 | -------------------------------------------------------------------------------- /login.php: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 10 | 11 |
12 |
13 |
Sistema de Chat en Línea en PHP y MySQL
14 |
15 |
16 |
17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 |
25 |
26 | 27 |
28 |
29 | 30 |
31 |
32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /php/config.php: -------------------------------------------------------------------------------- 1 | 0) ? $result = $row2['msg'] : $result = "No hay mensajes disponibles"; 9 | (strlen($result) > 28) ? $msg = substr($result, 0, 28) . '...' : $msg = $result; 10 | if (isset($row2['outgoing_msg_id'])) { 11 | ($outgoing_id == $row2['outgoing_msg_id']) ? $you = "Tu: " : $you = ""; 12 | } else { 13 | $you = ""; 14 | } 15 | ($row['status'] == "Fuera de Línea") ? $offline = "offline" : $offline = ""; 16 | ($outgoing_id == $row['unique_id']) ? $hid_me = "hide" : $hid_me = ""; 17 | 18 | $output .= ' 19 |
20 | 21 |
22 | ' . $row['fname'] . " " . $row['lname'] . ' 23 |

' . $you . $msg . '

24 |
25 |
26 |
27 |
'; 28 | } 29 | -------------------------------------------------------------------------------- /php/get-chat.php: -------------------------------------------------------------------------------- 1 | 0) { 13 | while ($row = mysqli_fetch_assoc($query)) { 14 | if ($row['outgoing_msg_id'] === $outgoing_id) { 15 | $output .= '
16 |
17 |

' . $row['msg'] . '

18 |
19 |
'; 20 | } else { 21 | $output .= '
22 | 23 |
24 |

' . $row['msg'] . '

25 |
26 |
'; 27 | } 28 | } 29 | } else { 30 | $output .= '
No hay mensajes disponibles. Una vez que envíe el mensaje, aparecerán aquí.
'; 31 | } 32 | echo $output; 33 | } else { 34 | header("location: ../login.php"); 35 | } 36 | -------------------------------------------------------------------------------- /php/images/1652660564avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/configuroweb/chat/1f220532ad7eedd4899724fe8977575084cf9342/php/images/1652660564avatar.png -------------------------------------------------------------------------------- /php/images/1652660638staff-avatar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/configuroweb/chat/1f220532ad7eedd4899724fe8977575084cf9342/php/images/1652660638staff-avatar.png -------------------------------------------------------------------------------- /php/images/1652670758chatbot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/configuroweb/chat/1f220532ad7eedd4899724fe8977575084cf9342/php/images/1652670758chatbot.png -------------------------------------------------------------------------------- /php/insert-chat.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /php/login.php: -------------------------------------------------------------------------------- 1 | 0) { 9 | $row = mysqli_fetch_assoc($sql); 10 | $user_pass = md5($password); 11 | $enc_pass = $row['password']; 12 | if ($user_pass === $enc_pass) { 13 | $status = "Disponible"; 14 | $sql2 = mysqli_query($conn, "UPDATE users SET status = '{$status}' WHERE unique_id = {$row['unique_id']}"); 15 | if ($sql2) { 16 | $_SESSION['unique_id'] = $row['unique_id']; 17 | echo "Proceso Exitoso"; 18 | } else { 19 | echo "Algo salió mal. ¡Inténtalo de nuevo!"; 20 | } 21 | } else { 22 | echo "¡Correo electrónico o la contraseña son incorrectos!"; 23 | } 24 | } else { 25 | echo "$email - ¡Este correo electrónico no existe!"; 26 | } 27 | } else { 28 | echo "¡Todos los campos de entrada son obligatorios!"; 29 | } 30 | -------------------------------------------------------------------------------- /php/logout.php: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /php/search.php: -------------------------------------------------------------------------------- 1 | 0){ 12 | include_once "data.php"; 13 | }else{ 14 | $output .= 'No user found related to your search term'; 15 | } 16 | echo $output; 17 | ?> -------------------------------------------------------------------------------- /php/signup.php: -------------------------------------------------------------------------------- 1 | 0) { 12 | echo "$email - ¡Este e-mail ya existe!"; 13 | } else { 14 | if (isset($_FILES['image'])) { 15 | $img_name = $_FILES['image']['name']; 16 | $img_type = $_FILES['image']['type']; 17 | $tmp_name = $_FILES['image']['tmp_name']; 18 | 19 | $img_explode = explode('.', $img_name); 20 | $img_ext = end($img_explode); 21 | 22 | $extensions = ["jpeg", "png", "jpg"]; 23 | if (in_array($img_ext, $extensions) === true) { 24 | $types = ["image/jpeg", "image/jpg", "image/png"]; 25 | if (in_array($img_type, $types) === true) { 26 | $time = time(); 27 | $new_img_name = $time . $img_name; 28 | if (move_uploaded_file($tmp_name, "images/" . $new_img_name)) { 29 | $ran_id = rand(time(), 100000000); 30 | $status = "Disponible"; 31 | $encrypt_pass = md5($password); 32 | $insert_query = mysqli_query($conn, "INSERT INTO users (unique_id, fname, lname, email, password, img, status) 33 | VALUES ({$ran_id}, '{$fname}','{$lname}', '{$email}', '{$encrypt_pass}', '{$new_img_name}', '{$status}')"); 34 | if ($insert_query) { 35 | $select_sql2 = mysqli_query($conn, "SELECT * FROM users WHERE email = '{$email}'"); 36 | if (mysqli_num_rows($select_sql2) > 0) { 37 | $result = mysqli_fetch_assoc($select_sql2); 38 | $_SESSION['unique_id'] = $result['unique_id']; 39 | echo "Proceso Exitoso"; 40 | } else { 41 | echo "¡Esta dirección de correo electrónico no existe!"; 42 | } 43 | } else { 44 | echo "Algo salió mal. ¡Inténtalo de nuevo!"; 45 | } 46 | } 47 | } else { 48 | echo "Cargue un archivo de imagen: jpeg, png, jpg"; 49 | } 50 | } else { 51 | echo "Cargue un archivo de imagen: jpeg, png, jpg"; 52 | } 53 | } 54 | } 55 | } else { 56 | echo "$email ¡No es un correo electrónico válido!"; 57 | } 58 | } else { 59 | echo "¡Todos los campos de entrada son obligatorios!"; 60 | } 61 | -------------------------------------------------------------------------------- /php/users.php: -------------------------------------------------------------------------------- 1 | 0){ 11 | include_once "data.php"; 12 | } 13 | echo $output; 14 | ?> -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css2?family=Poppins:wght@200;300;400;500;600;700&display=swap'); 2 | *{ 3 | margin: 0; 4 | padding: 0; 5 | box-sizing: border-box; 6 | text-decoration: none; 7 | font-family: 'Poppins', sans-serif; 8 | } 9 | body{ 10 | display: flex; 11 | align-items: center; 12 | justify-content: center; 13 | min-height: 100vh; 14 | background: #fc7d1c; 15 | padding: 0 10px; 16 | } 17 | .wrapper{ 18 | background: #fff; 19 | max-width: 450px; 20 | width: 100%; 21 | border-radius: 16px; 22 | box-shadow: 0 0 128px 0 rgba(0,0,0,0.1), 23 | 0 32px 64px -48px rgba(0,0,0,0.5); 24 | } 25 | 26 | /* Login & Signup Form CSS Start */ 27 | .form{ 28 | padding: 25px 30px; 29 | } 30 | .form header{ 31 | font-size: 25px; 32 | font-weight: 600; 33 | padding-bottom: 10px; 34 | border-bottom: 1px solid #e6e6e6; 35 | } 36 | .form form{ 37 | margin: 20px 0; 38 | } 39 | .form form .error-text{ 40 | color: #721c24; 41 | padding: 8px 10px; 42 | text-align: center; 43 | border-radius: 5px; 44 | background: #f8d7da; 45 | border: 1px solid #f5c6cb; 46 | margin-bottom: 10px; 47 | display: none; 48 | } 49 | .form form .name-details{ 50 | display: flex; 51 | } 52 | .form .name-details .field:first-child{ 53 | margin-right: 10px; 54 | } 55 | .form .name-details .field:last-child{ 56 | margin-left: 10px; 57 | } 58 | .form form .field{ 59 | display: flex; 60 | margin-bottom: 10px; 61 | flex-direction: column; 62 | position: relative; 63 | } 64 | .form form .field label{ 65 | margin-bottom: 2px; 66 | } 67 | .form form .input input{ 68 | height: 40px; 69 | width: 100%; 70 | font-size: 16px; 71 | padding: 0 10px; 72 | border-radius: 5px; 73 | border: 1px solid #ccc; 74 | } 75 | .form form .field input{ 76 | outline: none; 77 | } 78 | .form form .image input{ 79 | font-size: 17px; 80 | } 81 | .form form .button input{ 82 | height: 45px; 83 | border: none; 84 | color: #fff; 85 | font-size: 17px; 86 | background: #1984bc; 87 | border-radius: 5px; 88 | cursor: pointer; 89 | margin-top: 13px; 90 | } 91 | .form form .field i{ 92 | position: absolute; 93 | right: 15px; 94 | top: 70%; 95 | color: #ccc; 96 | cursor: pointer; 97 | transform: translateY(-50%); 98 | } 99 | .form form .field i.active::before{ 100 | color: #333; 101 | content: "\f070"; 102 | } 103 | .form .link{ 104 | text-align: center; 105 | margin: 10px 0; 106 | font-size: 17px; 107 | } 108 | .form .link a{ 109 | color: #333; 110 | } 111 | .form .link a:hover{ 112 | text-decoration: underline; 113 | } 114 | 115 | 116 | /* Users List CSS Start */ 117 | .users{ 118 | padding: 25px 30px; 119 | } 120 | .users header, 121 | .users-list a{ 122 | display: flex; 123 | align-items: center; 124 | padding-bottom: 20px; 125 | border-bottom: 1px solid #e6e6e6; 126 | justify-content: space-between; 127 | } 128 | .wrapper img{ 129 | object-fit: cover; 130 | border-radius: 50%; 131 | } 132 | .users header img{ 133 | height: 50px; 134 | width: 50px; 135 | } 136 | :is(.users, .users-list) .content{ 137 | display: flex; 138 | align-items: center; 139 | } 140 | :is(.users, .users-list) .content .details{ 141 | color: #000; 142 | margin-left: 20px; 143 | } 144 | :is(.users, .users-list) .details span{ 145 | font-size: 18px; 146 | font-weight: 500; 147 | } 148 | .users header .logout{ 149 | display: block; 150 | background: #333; 151 | color: #fff; 152 | outline: none; 153 | border: none; 154 | padding: 7px 15px; 155 | text-decoration: none; 156 | border-radius: 5px; 157 | font-size: 17px; 158 | } 159 | .users .search{ 160 | margin: 20px 0; 161 | display: flex; 162 | position: relative; 163 | align-items: center; 164 | justify-content: space-between; 165 | } 166 | .users .search .text{ 167 | font-size: 18px; 168 | } 169 | .users .search input{ 170 | position: absolute; 171 | height: 42px; 172 | width: calc(100% - 50px); 173 | font-size: 16px; 174 | padding: 0 13px; 175 | border: 1px solid #e6e6e6; 176 | outline: none; 177 | border-radius: 5px 0 0 5px; 178 | opacity: 0; 179 | pointer-events: none; 180 | transition: all 0.2s ease; 181 | } 182 | .users .search input.show{ 183 | opacity: 1; 184 | pointer-events: auto; 185 | } 186 | .users .search button{ 187 | position: relative; 188 | z-index: 1; 189 | width: 47px; 190 | height: 42px; 191 | font-size: 17px; 192 | cursor: pointer; 193 | border: none; 194 | background: #fff; 195 | color: #333; 196 | outline: none; 197 | border-radius: 0 5px 5px 0; 198 | transition: all 0.2s ease; 199 | } 200 | .users .search button.active{ 201 | background: #333; 202 | color: #fff; 203 | } 204 | .search button.active i::before{ 205 | content: '\f00d'; 206 | } 207 | .users-list{ 208 | max-height: 350px; 209 | overflow-y: auto; 210 | } 211 | :is(.users-list, .chat-box)::-webkit-scrollbar{ 212 | width: 0px; 213 | } 214 | .users-list a{ 215 | padding-bottom: 10px; 216 | margin-bottom: 15px; 217 | padding-right: 15px; 218 | border-bottom-color: #f1f1f1; 219 | } 220 | .users-list a:last-child{ 221 | margin-bottom: 0px; 222 | border-bottom: none; 223 | } 224 | .users-list a img{ 225 | height: 40px; 226 | width: 40px; 227 | } 228 | .users-list a .details p{ 229 | color: #67676a; 230 | } 231 | .users-list a .status-dot{ 232 | font-size: 12px; 233 | color: #468669; 234 | padding-left: 10px; 235 | } 236 | .users-list a .status-dot.offline{ 237 | color: #ccc; 238 | } 239 | 240 | /* Chat Area CSS Start */ 241 | .chat-area header{ 242 | display: flex; 243 | align-items: center; 244 | padding: 18px 30px; 245 | } 246 | .chat-area header .back-icon{ 247 | color: #333; 248 | font-size: 18px; 249 | } 250 | .chat-area header img{ 251 | height: 45px; 252 | width: 45px; 253 | margin: 0 15px; 254 | } 255 | .chat-area header .details span{ 256 | font-size: 17px; 257 | font-weight: 500; 258 | } 259 | .chat-box{ 260 | position: relative; 261 | min-height: 500px; 262 | max-height: 500px; 263 | overflow-y: auto; 264 | padding: 10px 30px 20px 30px; 265 | background: #f7f7f7; 266 | box-shadow: inset 0 32px 32px -32px rgb(0 0 0 / 5%), 267 | inset 0 -32px 32px -32px rgb(0 0 0 / 5%); 268 | } 269 | .chat-box .text{ 270 | position: absolute; 271 | top: 45%; 272 | left: 50%; 273 | width: calc(100% - 50px); 274 | text-align: center; 275 | transform: translate(-50%, -50%); 276 | } 277 | .chat-box .chat{ 278 | margin: 15px 0; 279 | } 280 | .chat-box .chat p{ 281 | word-wrap: break-word; 282 | padding: 8px 16px; 283 | box-shadow: 0 0 32px rgb(0 0 0 / 8%), 284 | 0rem 16px 16px -16px rgb(0 0 0 / 10%); 285 | } 286 | .chat-box .outgoing{ 287 | display: flex; 288 | } 289 | .chat-box .outgoing .details{ 290 | margin-left: auto; 291 | max-width: calc(100% - 130px); 292 | } 293 | .outgoing .details p{ 294 | background: #333; 295 | color: #fff; 296 | border-radius: 18px 18px 0 18px; 297 | } 298 | .chat-box .incoming{ 299 | display: flex; 300 | align-items: flex-end; 301 | } 302 | .chat-box .incoming img{ 303 | height: 35px; 304 | width: 35px; 305 | } 306 | .chat-box .incoming .details{ 307 | margin-right: auto; 308 | margin-left: 10px; 309 | max-width: calc(100% - 130px); 310 | } 311 | .incoming .details p{ 312 | background: #fff; 313 | color: #333; 314 | border-radius: 18px 18px 18px 0; 315 | } 316 | .typing-area{ 317 | padding: 18px 30px; 318 | display: flex; 319 | justify-content: space-between; 320 | } 321 | .typing-area input{ 322 | height: 45px; 323 | width: calc(100% - 58px); 324 | font-size: 16px; 325 | padding: 0 13px; 326 | border: 1px solid #e6e6e6; 327 | outline: none; 328 | border-radius: 5px 0 0 5px; 329 | } 330 | .typing-area button{ 331 | color: #fff; 332 | width: 55px; 333 | border: none; 334 | outline: none; 335 | background: #333; 336 | font-size: 19px; 337 | cursor: pointer; 338 | opacity: 0.7; 339 | pointer-events: none; 340 | border-radius: 0 5px 5px 0; 341 | transition: all 0.3s ease; 342 | } 343 | .typing-area button.active{ 344 | opacity: 1; 345 | pointer-events: auto; 346 | } 347 | 348 | /* Responive media query */ 349 | @media screen and (max-width: 450px) { 350 | .form, .users{ 351 | padding: 20px; 352 | } 353 | .form header{ 354 | text-align: center; 355 | } 356 | .form form .name-details{ 357 | flex-direction: column; 358 | } 359 | .form .name-details .field:first-child{ 360 | margin-right: 0px; 361 | } 362 | .form .name-details .field:last-child{ 363 | margin-left: 0px; 364 | } 365 | 366 | .users header img{ 367 | height: 45px; 368 | width: 45px; 369 | } 370 | .users header .logout{ 371 | padding: 6px 10px; 372 | font-size: 16px; 373 | } 374 | :is(.users, .users-list) .content .details{ 375 | margin-left: 15px; 376 | } 377 | 378 | .users-list a{ 379 | padding-right: 10px; 380 | } 381 | 382 | .chat-area header{ 383 | padding: 15px 20px; 384 | } 385 | .chat-box{ 386 | min-height: 400px; 387 | padding: 10px 15px 15px 20px; 388 | } 389 | .chat-box .chat p{ 390 | font-size: 15px; 391 | } 392 | .chat-box .outogoing .details{ 393 | max-width: 230px; 394 | } 395 | .chat-box .incoming .details{ 396 | max-width: 265px; 397 | } 398 | .incoming .details img{ 399 | height: 30px; 400 | width: 30px; 401 | } 402 | .chat-area form{ 403 | padding: 20px; 404 | } 405 | .chat-area form input{ 406 | height: 40px; 407 | width: calc(100% - 48px); 408 | } 409 | .chat-area form button{ 410 | width: 45px; 411 | } 412 | } 413 | -------------------------------------------------------------------------------- /unzipper.php: -------------------------------------------------------------------------------- 1 | prepareExtraction($archive, $destination); 25 | } 26 | 27 | if (isset($_POST['dozip'])) { 28 | $zippath = !empty($_POST['zippath']) ? strip_tags($_POST['zippath']) : '.'; 29 | // Resulting zipfile e.g. zipper--2016-07-23--11-55.zip. 30 | $zipfile = 'zipper-' . date("Y-m-d--H-i") . '.zip'; 31 | Zipper::zipDir($zippath, $zipfile); 32 | } 33 | 34 | $timeend = microtime(TRUE); 35 | $time = round($timeend - $timestart, 4); 36 | 37 | /** 38 | * Class Unzipper 39 | */ 40 | class Unzipper 41 | { 42 | public $localdir = '.'; 43 | public $zipfiles = array(); 44 | 45 | public function __construct() 46 | { 47 | // Read directory and pick .zip, .rar and .gz files. 48 | if ($dh = opendir($this->localdir)) { 49 | while (($file = readdir($dh)) !== FALSE) { 50 | if ( 51 | pathinfo($file, PATHINFO_EXTENSION) === 'zip' 52 | || pathinfo($file, PATHINFO_EXTENSION) === 'gz' 53 | || pathinfo($file, PATHINFO_EXTENSION) === 'rar' 54 | ) { 55 | $this->zipfiles[] = $file; 56 | } 57 | } 58 | closedir($dh); 59 | 60 | if (!empty($this->zipfiles)) { 61 | $GLOBALS['status'] = array('info' => '.zip or .gz or .rar files found, ready for extraction'); 62 | } else { 63 | $GLOBALS['status'] = array('info' => 'No .zip or .gz or rar files found. So only zipping functionality available.'); 64 | } 65 | } 66 | } 67 | 68 | /** 69 | * Prepare and check zipfile for extraction. 70 | * 71 | * @param string $archive 72 | * The archive name including file extension. E.g. my_archive.zip. 73 | * @param string $destination 74 | * The relative destination path where to extract files. 75 | */ 76 | public function prepareExtraction($archive, $destination = '') 77 | { 78 | // Determine paths. 79 | if (empty($destination)) { 80 | $extpath = $this->localdir; 81 | } else { 82 | $extpath = $this->localdir . '/' . $destination; 83 | // Todo: move this to extraction function. 84 | if (!is_dir($extpath)) { 85 | mkdir($extpath); 86 | } 87 | } 88 | // Only local existing archives are allowed to be extracted. 89 | if (in_array($archive, $this->zipfiles)) { 90 | self::extract($archive, $extpath); 91 | } 92 | } 93 | 94 | /** 95 | * Checks file extension and calls suitable extractor functions. 96 | * 97 | * @param string $archive 98 | * The archive name including file extension. E.g. my_archive.zip. 99 | * @param string $destination 100 | * The relative destination path where to extract files. 101 | */ 102 | public static function extract($archive, $destination) 103 | { 104 | $ext = pathinfo($archive, PATHINFO_EXTENSION); 105 | switch ($ext) { 106 | case 'zip': 107 | self::extractZipArchive($archive, $destination); 108 | break; 109 | case 'gz': 110 | self::extractGzipFile($archive, $destination); 111 | break; 112 | case 'rar': 113 | self::extractRarArchive($archive, $destination); 114 | break; 115 | } 116 | } 117 | 118 | /** 119 | * Decompress/extract a zip archive using ZipArchive. 120 | * 121 | * @param $archive 122 | * @param $destination 123 | */ 124 | public static function extractZipArchive($archive, $destination) 125 | { 126 | // Check if webserver supports unzipping. 127 | if (!class_exists('ZipArchive')) { 128 | $GLOBALS['status'] = array('error' => 'Error: Your PHP version does not support unzip functionality.'); 129 | return; 130 | } 131 | 132 | $zip = new ZipArchive; 133 | 134 | // Check if archive is readable. 135 | if ($zip->open($archive) === TRUE) { 136 | // Check if destination is writable 137 | if (is_writeable($destination . '/')) { 138 | $zip->extractTo($destination); 139 | $zip->close(); 140 | $GLOBALS['status'] = array('success' => 'Files unzipped successfully'); 141 | } else { 142 | $GLOBALS['status'] = array('error' => 'Error: Directory not writeable by webserver.'); 143 | } 144 | } else { 145 | $GLOBALS['status'] = array('error' => 'Error: Cannot read .zip archive.'); 146 | } 147 | } 148 | 149 | /** 150 | * Decompress a .gz File. 151 | * 152 | * @param string $archive 153 | * The archive name including file extension. E.g. my_archive.zip. 154 | * @param string $destination 155 | * The relative destination path where to extract files. 156 | */ 157 | public static function extractGzipFile($archive, $destination) 158 | { 159 | // Check if zlib is enabled 160 | if (!function_exists('gzopen')) { 161 | $GLOBALS['status'] = array('error' => 'Error: Your PHP has no zlib support enabled.'); 162 | return; 163 | } 164 | 165 | $filename = pathinfo($archive, PATHINFO_FILENAME); 166 | $gzipped = gzopen($archive, "rb"); 167 | $file = fopen($destination . '/' . $filename, "w"); 168 | 169 | while ($string = gzread($gzipped, 4096)) { 170 | fwrite($file, $string, strlen($string)); 171 | } 172 | gzclose($gzipped); 173 | fclose($file); 174 | 175 | // Check if file was extracted. 176 | if (file_exists($destination . '/' . $filename)) { 177 | $GLOBALS['status'] = array('success' => 'File unzipped successfully.'); 178 | 179 | // If we had a tar.gz file, let's extract that tar file. 180 | if (pathinfo($destination . '/' . $filename, PATHINFO_EXTENSION) == 'tar') { 181 | $phar = new PharData($destination . '/' . $filename); 182 | if ($phar->extractTo($destination)) { 183 | $GLOBALS['status'] = array('success' => 'Extracted tar.gz archive successfully.'); 184 | // Delete .tar. 185 | unlink($destination . '/' . $filename); 186 | } 187 | } 188 | } else { 189 | $GLOBALS['status'] = array('error' => 'Error unzipping file.'); 190 | } 191 | } 192 | 193 | /** 194 | * Decompress/extract a Rar archive using RarArchive. 195 | * 196 | * @param string $archive 197 | * The archive name including file extension. E.g. my_archive.zip. 198 | * @param string $destination 199 | * The relative destination path where to extract files. 200 | */ 201 | public static function extractRarArchive($archive, $destination) 202 | { 203 | // Check if webserver supports unzipping. 204 | if (!class_exists('RarArchive')) { 205 | $GLOBALS['status'] = array('error' => 'Error: Your PHP version does not support .rar archive functionality. How to install RarArchive'); 206 | return; 207 | } 208 | // Check if archive is readable. 209 | if ($rar = RarArchive::open($archive)) { 210 | // Check if destination is writable 211 | if (is_writeable($destination . '/')) { 212 | $entries = $rar->getEntries(); 213 | foreach ($entries as $entry) { 214 | $entry->extract($destination); 215 | } 216 | $rar->close(); 217 | $GLOBALS['status'] = array('success' => 'Files extracted successfully.'); 218 | } else { 219 | $GLOBALS['status'] = array('error' => 'Error: Directory not writeable by webserver.'); 220 | } 221 | } else { 222 | $GLOBALS['status'] = array('error' => 'Error: Cannot read .rar archive.'); 223 | } 224 | } 225 | } 226 | 227 | /** 228 | * Class Zipper 229 | * 230 | * Copied and slightly modified from http://at2.php.net/manual/en/class.ziparchive.php#110719 231 | * @author umbalaconmeogia 232 | */ 233 | class Zipper 234 | { 235 | /** 236 | * Add files and sub-directories in a folder to zip file. 237 | * 238 | * @param string $folder 239 | * Path to folder that should be zipped. 240 | * 241 | * @param ZipArchive $zipFile 242 | * Zipfile where files end up. 243 | * 244 | * @param int $exclusiveLength 245 | * Number of text to be exclusived from the file path. 246 | */ 247 | private static function folderToZip($folder, &$zipFile, $exclusiveLength) 248 | { 249 | $handle = opendir($folder); 250 | 251 | while (FALSE !== $f = readdir($handle)) { 252 | // Check for local/parent path or zipping file itself and skip. 253 | if ($f != '.' && $f != '..' && $f != basename(__FILE__)) { 254 | $filePath = "$folder/$f"; 255 | // Remove prefix from file path before add to zip. 256 | $localPath = substr($filePath, $exclusiveLength); 257 | 258 | if (is_file($filePath)) { 259 | $zipFile->addFile($filePath, $localPath); 260 | } elseif (is_dir($filePath)) { 261 | // Add sub-directory. 262 | $zipFile->addEmptyDir($localPath); 263 | self::folderToZip($filePath, $zipFile, $exclusiveLength); 264 | } 265 | } 266 | } 267 | closedir($handle); 268 | } 269 | 270 | /** 271 | * Zip a folder (including itself). 272 | * 273 | * Usage: 274 | * Zipper::zipDir('path/to/sourceDir', 'path/to/out.zip'); 275 | * 276 | * @param string $sourcePath 277 | * Relative path of directory to be zipped. 278 | * 279 | * @param string $outZipPath 280 | * Relative path of the resulting output zip file. 281 | */ 282 | public static function zipDir($sourcePath, $outZipPath) 283 | { 284 | $pathInfo = pathinfo($sourcePath); 285 | $parentPath = $pathInfo['dirname']; 286 | $dirName = $pathInfo['basename']; 287 | 288 | $z = new ZipArchive(); 289 | $z->open($outZipPath, ZipArchive::CREATE); 290 | $z->addEmptyDir($dirName); 291 | if ($sourcePath == $dirName) { 292 | self::folderToZip($sourcePath, $z, 0); 293 | } else { 294 | self::folderToZip($sourcePath, $z, strlen("$parentPath/")); 295 | } 296 | $z->close(); 297 | 298 | $GLOBALS['status'] = array('success' => 'Successfully created archive ' . $outZipPath); 299 | } 300 | } 301 | ?> 302 | 303 | 304 | 305 | 306 | 307 | File Unzipper + Zipper 308 | 309 | 391 | 392 | 393 | 394 |

395 | Status:
396 | Processing Time: seconds 397 |

398 |
399 |
400 |

Archive Unzipper

401 | 402 | 408 | 409 | 410 |

Enter extraction path without leading or trailing slashes (e.g. "mypath"). If left empty current directory will be used.

411 | 412 |
413 | 414 |
415 |

Archive Zipper

416 | 417 | 418 |

Enter path to be zipped without leading or trailing slashes (e.g. "zippath"). If left empty current directory will be used.

419 | 420 |
421 |
422 |

Unzipper version:

423 | 424 | 425 | -------------------------------------------------------------------------------- /users.php: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | 11 |
12 |
13 |
14 |
15 | 0) { 18 | $row = mysqli_fetch_assoc($sql); 19 | } 20 | ?> 21 | 22 |
23 | 24 |

25 |
26 |
27 | Cerrar Sesión 28 |
29 | 34 |
35 | 36 |
37 |
38 |
39 | 40 | 41 | 42 | 43 | 44 | --------------------------------------------------------------------------------